【问题标题】:Game object with composition and CCSpriteBatchNode具有合成和 CCSpriteBatchNode 的游戏对象
【发布时间】:2012-05-12 10:03:41
【问题描述】:

我目前正在 iPhone 上使用 cocos2d 和 box2d 开发游戏。
我阅读了很多关于游戏代码组织、游戏对象结构等的文章。 我首先通过继承自 CCSprite 的基类本身来开发我的游戏对象。 我有一个 CCSpriteBatchNode 来在一次绘制调用中绘制所有玩家可以与之交互的游戏项目。这很简单,因为我的 Item 类间接继承自 CCSprite,因此我可以轻松地将我的项目添加到 CCSpriteBatchNode。最重要的是,我可以依靠 cocos2d 来保留我的对象。

阅读文章后,我明白需要用更面向组合的风格而不是继承风格来重构我的代码。 所以我选择了一个继承自 NSObject 并具有一个或多个 CCSprite、一个 b2Body 等属性的 GameObject 基类。

我现在面临的问题是我不能再直接将我的游戏对象添加到 CCSpriteBatchNode 中。我首先认为我可以通过将 GameObject 的 sprite 属性添加到 CCSpriteBatchNode 来轻松解决问题。没关系,但谁保留拥有 CCSprite 的对象?如何从 CCSprite 轻松访问原始对象(userData/Object 是否正常)?

我应该创建一个数组来保留我的物品吗? 我想知道您将如何使用具有这种游戏对象结构的 CCSpriteBatchNode ?

已经有一个thread 关于未答复的问题,我真的很想听听这个主题。不是一个直截了当的答案,但有一些要更进一步的元素。

谢谢。

【问题讨论】:

    标签: cocos2d-iphone code-organization


    【解决方案1】:

    我个人不再推荐使用 NSObject 作为 cocos2d 类的基类。仅仅因为您失去了一些 cocos2d 的便利功能,例如调度,并且您可以轻松地在内存管理方面打自己的脚。

    您想要的是场景具有一个或多个精灵批处理节点的设置。您可以将它们视为您的精灵的图层。从 CCNode 派生的实际游戏对象(将它们视为 MVC 控制器)可以添加到任何地方,通常直接添加到场景中。

    scene
     + batch node 1
       + sprite 1
       + sprite 2
       + sprite n
     + batch node 2
       + sprite 1
       + sprite 2
       + sprite n
     + game node 1
     + game node 2
     + game node 3
     + game node n
    

    要记住的是,每个游戏节点都有一个或多个精灵作为实例变量,但它们不是节点的子节点。例如,游戏节点 1 类可能如下所示:

    game node 1 class
      CCSprite* sprite1;  // instance variable
      CCSprite* sprite2;  // instance variable
    

    现在,当您初始化游戏节点 1 及其精灵时,您可以将精灵添加到适当的精灵批处理节点。通常,您会希望像单例一样访问场景以访问其 sprite 批处理属性。

    sprite1 = [CCSprite spriteWithSpriteFrameName:@"doodle.png"];
    [[scene sharedScene].batchNode1 addChild:sprite1];
    sprite2 = [CCSprite spriteWithSpriteFrameName:@"splash.png"];
    [[scene sharedScene].batchNode2 addChild:sprite2];
    

    请注意,您不需要保留精灵,只要它们是精灵批处理节点的子节点。 addChild 方法为您保留它。实际上,它只是将它添加到一个执行保留的数组中。另外,如果您还在考虑“保留”,请务必使用start using ARC

    您不需要弄清楚如何访问 sprite 批处理中的 sprite。它可作为游戏节点类的实例变量使用,如果您愿意,还可以将其作为属性公开提供给其他类。

    游戏节点类显然运行所有对象的游戏逻辑,包括定位和修改精灵的属性。在游戏节点类中唯一需要注意的是从批处理节点中删除精灵,否则它可能会泄漏。为此,请覆盖清理方法:

    -(void) cleanup
    {
        [sprite1 removeFromParentAndCleanup:YES];
        sprite1 = nil;
        [sprite2 removeFromParentAndCleanup:YES];
        sprite2 = nil;
    
        [super cleanup];
    }
    

    将变量设置为 nil 很重要,因为清理后可能会运行代码,包括 dealloc 方法中的代码。您也可以删除 dealloc 中的精灵,但根据您的设置,由于对游戏节点类仍持有的精灵的引用,dealloc 甚至可能不会被调用。因此,如果精灵不是游戏节点类本身的子(或孙),则使用清理方法通常更安全。

    【讨论】:

    • 感谢您的回答。如果我明白你在说什么,添加游戏对象有两个步骤:将游戏对象添加为场景的节点(无视觉表示),然后添加游戏对象需要显示的任何视觉表示(在精灵中批处理节点或只是一个层)。
    • 我想在 sprite 批处理节点中访问 CCSprite 的原因是我沿 x 轴移动它们(或者更确切地说是它们“附加”到的主体)。也许这不是我应该这样做的方式......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多