Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I subclass CCSprite, CCNode, or NSObject?

Tags:

I see that certain texts always seem to subclass CCSprite. I read somewhere that it is not good to do that and that it is better to start with something basic. I wanted to find out what the pro game developers do in terms of game structure. That is subclass CCSprite or add CCSprite in a NSObject class ETC.

I hope my question makes sense.

like image 781
jini Avatar asked Aug 16 '11 21:08

jini


1 Answers

My preference is to subclass CCNode almost exclusively.

I would only ever subclass CCSprite, CCLabel and other internal Cocos2D classes if I needed the sprite, label or whatever to behave slightly differently from the base implementation. And subclassing would be a last resort measure if a category is insufficient. What most Cocos2D developers apparently don't understand is that CCSprite is in itself a complete class that does not need to be extended (subclassed) for representing game objects. But it's all too easy to fall into this habit because by creating a CCSprite subclass you get the visuals and you have a container for your game logic code. It's just not very OOP to do so.

If you think about it, as soon as you add some sort of game logic code to a CCSprite, it's not really just a CCSprite anymore, or is it? One good way to think about it is this: if you subclass a class (name it MyClass) and add custom code to it, would it make a lot of sense to subclass MyClass for other purposes, too? If not, then you shouldn't subclass.

To go with the widely used OOP analogy of the "Car" class: you subclass "Car" to make more specialized but still generic classes like "SportsCar", "Truck", "Van" but you wouldn't subclass "Car" to create a "Porsche 911 V-Turbo Model 6". Why not? Because the "SportsCar" class has all the aspects to create an instance of a SportsCar that then becomes a "Porsche 911 V-Turbo Model 6".

The other thing you have to consider is that a "Porsche 911 V-Turbo Model 6" would be a highly specialized class which doesn't have any other purpose than to define what that very specific car is about. It wouldn't make any sense to subclass the "Porsche 911" class because it has essentially lost its generic attributes and replaced them with very specific implementation details. If you have a class that you can't reasonably subclass any further, you've created a dead-end in your class hierarchy and are essentially writing functional code, not object-oriented code. Still, it's ok for simple games but it'll come back to haunt you if you dare to do more.

To summarize: you would subclass CCSprite only if your intention is to make a more specialized but still generally useable type of CCSprite. One example for that would be CCLabelTTF, which subclasses from CCSprite. It only adds the ability to create the CCSprite texture at runtime from a font and string. Another example for subclassing CCSprite would be if you needed a CCSprite that would update its texture from Google Maps to resemble a maps tile based on longitude and latitude coordinates and zoom level. It would still essentially be a dumb object whose only purpose is to display a rectangular image at a certain position. That's what a CCSprite is. A dumb object that displays a texture at a certain position.

The question really is about this: is ("is a") your game object a sprite, or does it have ("has a") a sprite for its visual representation? The answer should always be the latter. The common rule for subclassing is the "is a" relationship, in case of "has a" it's time for the composite pattern. If in doubt, and both seem to apply, always err on the "has a" side because that always works.

Why would I say that a game object is not a sprite, but has a sprite? Clearly both are applicable. The answer: the game object "is a" sprite only as long as it can be represented by a single sprite and nothing else. But in fact, your game object might have to be represented by multiple sprites, or a sprite, a label and some particle effects. That means the "is a" relationship is much more likely to break as the app is being developed, and that means additional refactoring work.

By using a CCNode as the base class for your game objects, and adding the visual nodes onto that base node, you can also use the base node as the controller object for the game object's view(s). Which means it'll better conform to the Model-View-Controller (MVC) pattern.

Finally I wouldn't subclass NSObject for anything that should be in the cocos2d view hierarchy, or keeps a reference to something that's in the cocos2d view hierarchy. For the simple reason that NSObject subclasses don't offer any of the standard features of a CCNode (scheduling, adding child nodes, relative positioning of child nodes) and most importantly, it's difficult to use NSObject subclasses together with Cocos2D's rather automatic memory management of node classes.

Without going into detail, the simple rule is that if a subclass has an instance variable that is a Cocos2D node, it should itself be a Cocos2D node so that memory management and all other aspects are easy and foolproof. As far as Cocos2D is concerned, the CCNode class is the root class for the view hierarchy, so it resembles the UIResponder class with the ability to take on the role of the UIView and/or UIViewController classes (both subclass from UIResponder by the way) on occassions.

In short: subclass CCNode, then use composition/aggregation pattern for the visual aspects of the class.

like image 190
LearnCocos2D Avatar answered Oct 13 '22 13:10

LearnCocos2D