【问题标题】:Cocos2d: 6 doubts on usage of CCSpriteBatchNodeCocos2d:CCSpriteBatchNode使用的6个疑惑
【发布时间】:2012-09-09 17:53:23
【问题描述】:

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

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

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

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

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

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

        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?

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


关于 3 的其他注意事项

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

其他人会建议通过使用 self.parent.....parent 并正确转换来引用 MainScene。

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

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

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

【问题讨论】:

    标签: cocos2d-iphone ccsprite atlassprites


    【解决方案1】:
    1. 正确,但“绘图调用”不等同于执行draw 方法。绘制调用是 OpenGL 状态的更改,需要执行昂贵的操作来重置状态机。绑定新纹理或更改变换符合要求。
    2. 正确。
    3. 正确。
    4. 不需要这样做。动画在精灵上运行。所以只需要对精灵进行批处理。如果一个动画帧不是来自同一个纹理图集,CCSpriteBatchNode 会在动画尝试使用这样的帧时报错。
    5. 最好。在 CCSpriteBatchNode 中添加/删除精灵比添加/删除任何其他节点更昂贵。因为精灵批处理节点的四边形需要更新。尽管只有当您有许多子节点并经常添加/删除时,它可能才会有任何区别。
    6. 没有,也没有。见my answer here

    关于 3 的其他注意事项:

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

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

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

    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。您应该只在场景实例已经运行时访问它,即它仅供该特定场景的子节点使用。

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

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

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

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

    【讨论】:

    • 您建议的半单例方法与LearnCocos2D中的ShootEmUp示例基本相同。我确实喜欢它,但我只有一个问题,因此我开始重新考虑代码结构。当我在 GameScene 中并选择返回主菜单场景(通过 SharedDirector.replaceScene)时,GameScene 实例仍将保留在内存中,直到从主场景中我选择再次推送 GameScene(例如 [[CCDirector sharedDirector] replaceScene :[GameScene sceneWithId:1])。你能帮忙澄清一下吗?否则,非常感谢您提供详尽的帖子
    猜你喜欢
    • 1970-01-01
    • 2020-11-02
    • 2010-12-27
    • 2017-02-16
    • 2013-09-06
    • 2013-08-12
    • 2018-11-30
    • 2016-05-30
    • 1970-01-01
    相关资源
    最近更新 更多