【发布时间】:2011-10-28 10:42:51
【问题描述】:
我看到某些文本似乎总是从 CCSprite 子类化。我在某处读到这样做不好,最好从基本的东西开始。我想了解职业游戏开发者在游戏结构方面做了什么。即子类 CCSprite 或在 NSObject 类 ETC 中添加 CCSprite。
我希望我的问题有意义。
【问题讨论】:
标签: ios cocos2d-iphone
我看到某些文本似乎总是从 CCSprite 子类化。我在某处读到这样做不好,最好从基本的东西开始。我想了解职业游戏开发者在游戏结构方面做了什么。即子类 CCSprite 或在 NSObject 类 ETC 中添加 CCSprite。
我希望我的问题有意义。
【问题讨论】:
标签: ios cocos2d-iphone
你的问题绝对有道理。
这基本上是一个架构问题。如果您的游戏主要基于“动画”,我会选择 CCSprite 的子类。如果您的游戏主要基于某种逻辑,可能是 RPG 或其他任何东西,那么屏幕表示实际上只是游戏状态的可能视图之一。因此,在我看来,它应该是代表游戏状态的对象树中对象的一部分。
换句话说:如果你的游戏状态本质上是一个场景,那么子类 CCSprite,因为 Cocos2D 在管理场景方面可能比你好得多。如果您的游戏状态是“其他”,您可能应该考虑构建您自己的该状态表示,并使您的精灵成为游戏对象的一部分。如果您决定更改渲染,这也将允许您“切换”图形引擎。例如,您可能正在 Cocos2D 中使用 2D 表示形式制作 RPG。过了一会儿,你把你的演示展示给育碧,他们爱上了它,并给你 2000 万美元来完成它,但他们要求 3D 渲染。如果你想继承 CCSprite,你必须重做所有的游戏。如果您打算将 CCSprite/CCNode 集成到一个 NSObject 派生类中,那么您就可以开始了。
当然,为了...示例:D
【讨论】:
如果您在这次 Cocos2D 之旅中遇到这个问题,请将 CCSprite 子类化并完成。您现在不会创建任何需要微调类的高级技术的东西。我这样说并不是对你能力的侮辱,而是作为一个曾经有过这个问题的人。
当您开始怀疑是否需要重写 CCNode 的 OpenGL 方法调用时,您将需要仔细考虑子类化选项。对 CCSprite 进行子类化后,您可以获得所有较低级别的所有方法和属性,让您能够发现、学习和前进。
简而言之:子类 CCSprite。
【讨论】:
我的偏好是几乎完全是 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,然后对类的视觉方面使用组合/聚合模式。
【讨论】:
在我看来,游戏中的对象不是精灵。 Sprite 是对象的表示,这意味着您需要创建 GameObject 子类 NSObject(可能是 CCNode)..
总结一下:NSObject 或 CCSprite 的子类是类结构,你需要使用你的代码风格。
【讨论】: