【问题标题】:Should I subclass CCSprite, CCNode, or NSObject?我应该继承 CCSprite、CCNode 还是 NSObject?
【发布时间】:2011-10-28 10:42:51
【问题描述】:

我看到某些文本似乎总是从 CCSprite 子类化。我在某处读到这样做不好,最好从基本的东西开始。我想了解职业游戏开发者在游戏结构方面做了什么。即子类 CCSprite 或在 NSObject 类 ETC 中添加 CCSprite。

我希望我的问题有意义。

【问题讨论】:

    标签: ios cocos2d-iphone


    【解决方案1】:

    你的问题绝对有道理。

    这基本上是一个架构问题。如果您的游戏主要基于“动画”,我会选择 CCSprite 的子类。如果您的游戏主要基于某种逻辑,可能是 RPG 或其他任何东西,那么屏幕表示实际上只是游戏状态的可能视图之一。因此,在我看来,它应该是代表游戏状态的对象树中对象的一部分。

    换句话说:如果你的游戏状态本质上是一个场景,那么子类 CCSprite,因为 Cocos2D 在管理场景方面可能比你好得多。如果您的游戏状态是“其他”,您可能应该考虑构建您自己的该状态表示,并使您的精灵成为游戏对象的一部分。如果您决定更改渲染,这也将允许您“切换”图形引擎。例如,您可能正在 Cocos2D 中使用 2D 表示形式制作 RPG。过了一会儿,你把你的演示展示给育碧,他们爱上了它,并给你 2000 万美元来完成它,但他们要求 3D 渲染。如果你想继承 CCSprite,你必须重做所有的游戏。如果您打算将 CCSprite/CCNode 集成到一个 NSObject 派生类中,那么您就可以开始了。

    当然,为了...示例:D

    【讨论】:

      【解决方案2】:

      如果您在这次 Cocos2D 之旅中遇到这个问题,请将 CCSprite 子类化并完成。您现在不会创建任何需要微调类的高级技术的东西。我这样说并不是对你能力的侮辱,而是作为一个曾经有过这个问题的人。

      当您开始怀疑是否需要重写 CCNode 的 OpenGL 方法调用时,您将需要仔细考虑子类化选项。对 CCSprite 进行子类化后,您可以获得所有较低级别的所有方法和属性,让您能够发现、学习和前进。

      简而言之:子类 CCSprite。

      【讨论】:

        【解决方案3】:

        我的偏好是几乎完全是 CCNode 的子类

        如果我需要精灵、标签或其他与基本实现稍有不同的行为,我只会继承 CCSprite、CCLabel 和其他内部 Cocos2D 类。如果类别不足,子类化将是最后的手段。大多数 Cocos2D 开发者显然不明白的是,CCSprite 本身就是一个完整的类,不需要扩展(子类化)来表示游戏对象。但是很容易陷入这种习惯,因为通过创建 CCSprite 子类,您可以获得视觉效果,并且您拥有游戏逻辑代码的容器。这样做并不是很 OOP。

        如果你想一想,一旦你将某种游戏逻辑代码添加到 CCSprite 中,它就不再只是一个 CCSprite,或者是吗?考虑它的一个好方法是:如果您子类化一个类(将其命名为 MyClass)并向其添加自定义代码,那么将 MyClass 子类化用于其他目的是否也很有意义?如果不是,那么你不应该子类化。

        使用广泛使用的 OOP 类比“Car”类:您将“Car”子类化以创建更专业但仍然通用的类,例如“SportsCar”、“Truck”、“Van”,但您不会子类化“ Car”打造“Porsche 911 V-Turbo Model 6”。为什么不?因为“SportsCar”类具有创建SportsCar 的实例的所有方面,该SportsCar 然后成为“Porsche 911 V-Turbo Model 6”。

        您必须考虑的另一件事是,“Porsche 911 V-Turbo Model 6”将是一个高度专业化的类别,除了定义该非常具体的汽车的用途之外没有任何其他目的。子类化“Porsche 911”类没有任何意义,因为它基本上失去了其通用属性,并用非常具体的实现细节代替了它们。如果您有一个无法合理地进一步子类化的类,那么您在类层次结构中创建了一个死胡同,并且本质上是在编写功能代码,而不是面向对象的代码。不过,对于简单的游戏来说还可以,但如果你敢于做更多的事情,它就会回来困扰你。

        总而言之:只有当您的意图是制作更专业但仍然普遍可用的 CCSprite 类型时,您才会将 CCSprite 子类化。一个例子是 CCLabelTTF,它是 CCSprite 的子类。它只增加了在运行时从字体和字符串创建 CCSprite 纹理的能力。另一个子类化 CCSprite 的示例是,如果您需要一个 CCSprite,它可以从 Google 地图更新其纹理,以类似于基于经度和纬度坐标和缩放级别的地图图块。它本质上仍然是一个愚蠢的对象,其唯一目的是在某个位置显示一个矩形图像。这就是CCSprite。在特定位置显示纹理的哑对象。

        问题真的是这样的:is(“is a”)你的游戏对象是一个精灵,还是(“has a”)一个精灵它的视觉表现?答案应该永远是后者。子类化的通用规则是“is a”关系,如果“has a”是composite pattern的时间。如果有疑问,并且两者似乎都适用,请始终在“有”方面犯错,因为这总是有效的。

        为什么我会说游戏对象不是精灵,而是有精灵?显然两者都适用。答案是:游戏对象“是一个”精灵,只要它可以由单个精灵表示,而不是其他任何东西。但实际上,您的游戏对象可能必须由多个 sprite 表示,或者一个 sprite、一个标签和一些粒子效果。这意味着随着应用程序的开发,“is a”关系更有可能被打破,这意味着额外的重构工作。

        通过使用 CCNode 作为游戏对象的基类,并将可视节点添加到该基节点上,您还可以将基节点用作游戏对象视图的控制器对象。这意味着它会更好地符合模型-视图-控制器 (MVC) 模式。

        最后,我不会为任何应该在 cocos2d 视图层次结构中的东西子类化 NSObject,或者保留对 cocos2d 视图层次结构中的东西的引用。原因很简单,NSObject 子类不提供 CCNode 的任何标准特性(调度、添加子节点、子节点的相对定位),最重要的是,很难将 NSObject 子类与 Cocos2D 的相当自动的内存管理一起使用节点类。

        不赘述,简单的规则是,如果子类有一个实例变量是 Cocos2D 节点,那么它本身就应该是 Cocos2D 节点,这样内存管理和其他所有方面都变得简单和万无一失。就 Cocos2D 而言,CCNode 类是视图层次结构的根类,因此它类似于 UIResponder 类,能够承担 UIView 和/或 UIViewController 类的角色(都是 UIResponder 的子类)方式)在场合。

        简而言之:子类 CCNode,然后对类的视觉方面使用组合/聚合模式。

        【讨论】:

        • 感谢您的详细回答,我也有机会阅读您的书。再次感谢
        • @LearnCocos2D,这与您书中发布的代码示例相反。在第 5 章中,您推荐子类化 CCNode,但所有代码示例都是子类化 CCSprite。有什么原因吗?
        • 没有充分的理由,第一版的剩余部分,对于小型项目来说已经足够了。
        • 这种方法非常健壮。它也被 Mick West 在 Tony Hawk 系列中采用:cowboyprogramming.com/2007/01/05/evolve-your-heirachy
        【解决方案4】:

        在我看来,游戏中的对象不是精灵。 Sprite 是对象的表示,这意味着您需要创建 GameObject 子类 NSObject(可能是 CCNode)..

        总结一下:NSObject 或 CCSprite 的子类是类结构,你需要使用你的代码风格。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-06-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-14
          • 1970-01-01
          • 2012-02-24
          • 2017-02-17
          • 2012-05-29
          相关资源
          最近更新 更多