Cocos2d:CCSpriteBatchNode使用的6个疑惑 [英] Cocos2d: 6 doubts on usage of CCSpriteBatchNode

查看:17
本文介绍了Cocos2d:CCSpriteBatchNode使用的6个疑惑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道如何优化 CCSpriteBatchNode 的使用.换句话说,我理解:

I am wondering how to optimize the usage of CCSpriteBatchNode. In other words I understand that:

  • 1) 每个 CCSpriteBatchNode 实例对 draw 方法执行一次调用,从而减少 OpenGL 调用,从而显着提高性能
  • 2) 每个 CCSpriteBatchNode 只能引用一个纹理图集

我不能 100% 确定,我希望您的回答是:

What I am not 100% sure and I would like your answer is:

  • 3) 如果我有一个纹理图集,例如game-art-hd.png,并创建几个各种类中的 CCSpriteBatchNode 我会收到多个绘图调用吗?换句话说,我假设 CCSpriteBatchNode 的每个实例都会调用自己的draw方法,导致多次GL绘图调用和性能低于拥有一个共享批处理节点.我说的对吗?

  • 3) If I have one texture atlas, e.g. game-art-hd.png, and create several CCSpriteBatchNode in various classes will I get mutliple draw calls? In other words, I assume that each instance of CCSpriteBatchNode will call its own draw method, resulting in multiple GL drawing calls and less performance than having one shared batch node. Am I right?

- 4) 如果我在 Sprite 上使用由多个帧组成的动画,我猜想我应该将动画帧添加到 Sprite 批处理节点.如何我可以这样做吗?

下面是我通常如何为精灵设置动画的代码片段.可以注意到,精灵帧没有添加到精灵批处理节点.为了获得更好的性能,我可能应该这样做在初始化时.这是正确的吗?

Following there is a code snippet on how I normally animate a sprite. As can be noticed the sprite frames are not added to the sprite batch node. For better performance I should probably do this at initialization time. Is this correct?

    NSMutableArray* frames = [[NSMutableArray alloc]initWithCapacity:2];

    for (int i = 0; i < 4; i++)
    {
        NSString*bulletFrame = [NSString stringWithFormat:@"animation-%i.png", i];            
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:bulletFrame];
        [frames addObject:frame];
    }
    CCAnimation* anim = [CCAnimation animationWithFrames:frames delay:0.1f];
    CCAnimate* animate = [CCAnimate actionWithAnimation:anim];
    CCRepeatForever* repeat = [CCRepeatForever actionWithAction:animate];
    [self runAction:repeat];

} 

  • 5) 部分参考 4. 你确认是宁愿避免在运行时向 sprite 批处理节点添加和删除 sprite?

  • 5) Partially refering to 4. do you confirm that is prefer to avoid adding and removing sprites to a sprite batch node at runtime?

    6) CCSpriteBatchNode 是否只考虑可见设置为 true 的精灵或位置实际上在屏幕区域之外的精灵?

    6) Will CCSpriteBatchNode consider only sprites that have visible set to true or sprites that have a position that is actually outside the screen area?

    关于 3 的其他注意事项

    为了解决我在 3. 中的假设,并减少 CCSpriteBatchNode 实例的数量,我的解决方案将遵循 @Suboptimus 在此 答案.我喜欢初始化希望与 MainScene 类共享相同批处理节点的类的建议方法,而不是让它们通过 self.parent.parent.(...).parent.finallysharedbatchNode 访问 MainScene

    In order to address my assumption in 3., and reduce the number of CCSpriteBatchNode instances, my solution would follow what suggested by @Suboptimus in this answer. I like the suggested approach of initializing classes that want to share the same batch node with the MainScene class, rather than having them to access the MainScene via self.parent.parent.(...).parent.finallysharedbatchNode

    其他人会建议通过使用 self.parent.....parent 并正确投射来引用 MainScene.

    Other people would instead suggest to refer to the MainScene via using self.parent.....parent and casting it correctly.

    这也是软件工程方面的最佳方法吗?

    我更喜欢使用对 MainScene 类的显式引用来明确添加精灵的位置.如果我在团队中工作或更改类层次结构,这应该会有所帮助.但是这样做的缺点是,如果我想将后续精灵添加到批处理节点,我需要"存储对它的引用,从而导致需要维护更多代码.

    I prefer making it clear where the sprites are added by using an explicit reference to the MainScene class.. this should help if I am working in team or if I change the class hierarchy. But the downside of this is that I "need" to store a reference to it if I want to add subsequently sprites to the batch node, resulting in more code to maintain.

    我问这个问题的原因是,如果我发现我传统的软件工程"思维和Cocos2d 父节点"层次结构方法之间存在轻微冲突.我是游戏编程的新手,我想了解在大型团队中工作的经验丰富的游戏开发人员使用哪种方法:).H

    The reason I am asking this question is that if find a slight clash between my traditional "Software Engineering" mind and the "Cocos2d parent-node" hierarchy approach. I am new to game programming and I'd like to understand which approach is the one that experienced game developers that work in large teams use :). H

    推荐答案

    1. 正确,但绘图调用"不等同于执行 draw 方法.绘制调用是 OpenGL 状态的更改,需要执行昂贵的操作来重置状态机.绑定新纹理或更改变换符合要求.
    2. 正确.
    3. 正确.
    4. 无需这样做.动画在精灵上运行.所以只需要对精灵进行批处理.如果一个动画帧不是来自同一个纹理图集,CCSpriteBatchNode 会在动画尝试使用这样的帧时报错.
    5. 最好.在 CCSpriteBatchNode 中添加/删除精灵比添加/删除任何其他节点更昂贵.因为精灵批处理节点的四边形需要更新.尽管只有当您有许多子节点并经常添加/删除时,它可能才会有任何区别.
    6. 没有也没有.请参阅我的答案.
    1. Correct, but a "draw call" is not equivalent to executing the draw method. A draw call is a change in the OpenGL state that requires performing an expensive operation to reset the statemachine. Binding a new texture or changing transform fit the bill.
    2. Correct.
    3. Correct.
    4. No need to do that. Animations run on sprites. So only the sprite needs to be batched. If one animation frame is not from the same texture atlas, CCSpriteBatchNode will complain when the animation tries to use such a frame.
    5. It's preferable. Add/Remove of sprites in a CCSpriteBatchNode is more expensive than add/remove of any other node. Because the sprite batch node's quads need to be updated. Though it probably only makes any difference if you have many child nodes and add/remove frequently.
    6. No and no. See my answer here.

    关于 3 的其他注意事项:

    如果你的场景层次不是太深,你可以偶尔使用 self.parent 或者 self.parent.parent 但只有在父-父关系实际上是固定的情况下(即从一个精灵批处理精灵绕过精灵批处理节点以到达底层的真正"父级).但我不建议更深入.有关 self.parent 和避免保留周期的技术,请参阅我的答案.

    If your scene hierarchy is not too deep, you can go with self.parent or maybe self.parent.parent on occasion but only where the parent-parent relationship is practically fixed (ie from a sprite batched sprite bypassing the sprite batch node in order to get to the underlying "true" parent). But I wouldn't recommend going any deeper. See my answer here for techniques for both self.parent and avoiding retain cycles.

    self.parent.parent.(…).parent 的问题在于,如果您需要更改父子关系,例如通过在等级制度.然后这将与 EXC_BAD_ACCESS 严重崩溃并且很难调试,因为您必须检查每个父级和父级的父级以查看它到底是什么类型的对象.访问超过 3 个或更多层次结构的父级我不会认为是不好的做法.这是一种糟糕的做法.

    The problem with self.parent.parent.(…).parent is that this completely breaks if you need to change the parent child relationship, for example by adding or removing a parent node in the hierarchy. This will then crash badly with EXC_BAD_ACCESS and it's hard to debug because you will have to check each parent and parent's parent to see what kind of object it really is. Accessing parents over 3 or more levels of the hierarchy I wouldn't consider bad practice. It's a terrible practice.

    就个人而言,为了访问共享精灵批次等常用节点,我更喜欢MainScene"在其处于活动状态时成为临时单例类的解决方案.然后您可以从任何子节点执行以下操作:

    Personally, for access to commonly used nodes like shared sprite batches, I prefer the solution where the "MainScene" becomes a temporary Singleton class for the time while it is active. Then you can do the following from any child node:

    CCSpriteBatchNode* mainBatch = [MainScene sharedMainScene].spriteBatchNode;
    

    创建这个临时单例:

    static MainScene* instance;
    -(id) init
    {
        self = [super init];
        if (self)
        {
            instance = self;
        }
        return self;
    }
    -(void) dealloc
    {
        instance = nil;
    }
    -(MainScene*) sharedMainScene
    {
        NSAssert(instance, @"MainScene is not initialized!");
        return instance;
    }
    

    与真正的单例的不同之处在于,如果它还不存在,它不会初始化实例.因此 sharedMainScene 中的 NSAssert.您应该只在场景实例已经运行时访问它,即它仅供该特定场景的子节点使用.

    The difference to a real singleton is that it doesn't initialize the instance if it doesn't exist yet. Hence the NSAssert in sharedMainScene. You should only access the scene instance while it is already running, ie it's only to be used by child nodes of that particular scene.

    这个半单例允许访问场景的所有属性.您还可以发送场景可以中继到其他节点的消息.或者将场景中需要移除但在碰撞处理过程中无法移除的物理对象排入队列.

    This semi-singleton allows access to all of the scene's properties. You can also send messages that the scene could relay to other nodes. Or enqueue physics objects in the scene that need to be removed, but can't be removed during collision handling itself.

    如果那个单身人士打扰了你,总有可能从导演那里得到跑步场景:

    And if that singleton bothers you, there's always the possibility to get the running scene from the director:

    MainScene* mainScene = (MainScene*)[CCDirector sharedDirector].runningScene;
    

    只有在 runningScene 确实是 MainScene 对象时,才应该小心转换到 MainScene.isKindOfClass:检查或断言是否正常.

    You should be careful casting to the MainScene only if the runningScene is really a MainScene object. An isKindOfClass: check or assert is in order.

    这篇关于Cocos2d:CCSpriteBatchNode使用的6个疑惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆