1

In my project (a game) I have multiple objects that are manipulated by touch, so I thought that having all touchable objects as subclasses of a "Touchable" abstract class would be a good idea, something along the lines of:

Touchable is a subclass of CCSprite

Box is a subclass of Touchable

Motor is a subclass of Touchable

therefore Box and Motor are CCSprites, and they inherit the common methods of Touchable, and can override them

Is this a correct way to go about this, or is there some other way to tackle this hierachy?

omz
  • 53,243
  • 5
  • 129
  • 141
Sam P
  • 453
  • 6
  • 19

2 Answers2

3

I previously explained why subclassing CCSprite is almost always a bad idea.

"Touchable" as the name suggests is an ability of an object. A node can either be touched, or it can not. Moreover, this must not be restricted to sprites. What if later on you want a touchable label, a touchable particle effect, or some other touchable node class?

Obviously you can't subclass CCNode to make it touchable and then turn subclasses of that touchable node class back into sprites, labels, etc. because cocos2d already established a class hierarchy - this is where the inflexibility of such a hierarchical system surfaces, and starts becoming a real pain.

You could add such a touchable (or killable, flying, jumping, drivable, swipeable, etc) ability to any object, at any time, and you could take it away at any time as well. That makes it a candidate for a plugin class (a component). Any ability, especially those that may be temporary, should not be part of a superclass but instead be additional objects that you can add to an existing object, and enable/disable as needed.

One way to go about this is to use the userObject property of nodes. Write an Abilities container class, and assign it to the userObject of your nodes. Then add the desired Ability classes to the container of a node. The node then updates the userObject container class by forwarding the update method, which forwards update to all abilities. Or the Ability container itself registers with CCScheduler to receive updates. The only thing the container class and ability classes need is a (weak) reference to the owning node.

Community
  • 1
  • 1
CodeSmile
  • 64,284
  • 20
  • 132
  • 217
2

Depends on if "Touchable" represents a random set of behaviors that each class must explicitly implement to support or if there can be a single implementation that "just works" with inheritance (with, maybe, a bit of customization).

If the former, then your thinking is mostly correct. If the latter, then Jack's suggestion of using an @protocol (which is a lot like an Interface in Java) makes sense.

Personally, I'd keep it really simple. Start with an SPAbstractSprite class that is a subclass of CCSprite. Then, subclass that into SPBox and SPMotor.

Start your implementation in SPBox and/or SPMotor and, as common things fall out, refactor them into SPAbstractSprite.

As for the notion of "touchable", I wouldn't worry about trying to make that a named thing for now. Approach it the same way as above; implement touchable support in your motor or box, then refactor up to the abstract parent class later.

I am, quite admittedly, a very design-and-code-interleaved person, though, and fully acknowledge that there are those who really like to sit down and draw out a nice set of box/lines/hierarchy before writing a line of code.

In any case, you should note that the class hierarchies across the Apple provided classes and examples tend to be quite shallow and don't tend to do a huge amount of this abstraction, though abstraction is still used heavily (UIView is an abstract container for all the view like goop that all those subclasses need, for example).

bbum
  • 162,346
  • 23
  • 271
  • 359
  • Thanks for your answer. I am also a design-and-code person, but sometimes it is useful to sit and think about the structure of your code, because it can lead to less work in the future. "Touchable" represents the fact that these classes interact with the user by being touched, which means it is really just there to be implemented as "onTouchBegin" "onTouchMoved" "onTouchEnded". I guess there's no need to subclass them, but then what's wrong with a thought experiment here and there? – Sam P Oct 11 '12 at 00:00
  • For example, a box creates a joint between the player and box when touched, moves the box within the bounds of the joint when moved, and destroys the joint when released. A motor activates when touched, and deactivates when touched again. – Sam P Oct 11 '12 at 00:01
  • 1
    (Huh, a downvote?) Oh, no, there is absolutely nothing wrong with sitting and thinking it through. – bbum Oct 11 '12 at 18:05