Reputation: 946
I was reading Learn Cocos2d 2; and stumbled across this problem: in a game scene one might have thousands of entities below the scene hierarchy and all these entities might want to talk to the topmost scene object. The author of Learn Cocos2d 2 suggests using a global variable like this
static GameLayer* sharedGameLayer;
+(GameLayer*) sharedGameLayer
{
NSAssert(sharedGameLayer != nil, @"GameScene instance not yet initialized!");
return sharedGameLayer;
}
+(id) scene
{
CCScene *scene = [CCScene node];
GameLayer *layer = [GameLayer node];
[scene addChild: layer];
InputLayer* inputLayer = [InputLayer node];
[scene addChild:inputLayer z:1 tag:GameSceneLayerTagInput];
return scene;
}
Personally I think this approach unreliable: imagine a player entity want to know the touch input from another layer in the scene, so it calls sharedGameLayer and assuming it is the parent that it actually resides in it just works on from there. But how can it be so sure? what if this sharedGameLayer is another instance that someone else has allocated? Of course there can only be one scene at a time in cocos2d, and so this approach just might work most of the time without any problem. But from a design point of view, I still find such approach lacking.
I've thought about two alternatives:
using the proper (old) delegate approach. Assigning the correct delegate/delegator relationship at each level. However, this means thousands lines of possibly duplicate code and is not neat from my perspective
using NSNotification (or KVO?) to broadcast messages from the children level, and let the parent respond accordingly. But does this mean unnecessary overhead for the system
At this point I'm quite lost, can someone tell me about the general idiom that experienced programmers might use?
Upvotes: 0
Views: 76
Reputation: 64478
You may want to read my "Strategies for accessing other nodes in the hierarchy" guide. Plenty of options to choose from with pros and cons.
Upvotes: 1
Reputation: 5664
In most cases, the leaves of your tree of CCNode
s, like for exampe the "player entity" you mention, will only persist as long as the containing CCScene
is on the CCDirector
's scenes stack. Once this scene gets popped, it will receive a dealloc
message and thus removeAll
(its)Children
. This in turn will dealloc
these children, including your "player entitity". The last message your "player entity" will receive is a dealloc
during which all parent nodes are still alive (although in the process of being destructed), so there will never be a case where children would request an invalid sharedGameLayer
. However, if you want to carry over any children to another scene, you will have to take great care in so many ways that this is hardly anything to be encouraged if not absolutely necessary. For example, your specific block of code would have to be improved so that sharedGameLayer
will return nil
if the scene is no longer active, and your "player entity" might want to check this return value.
The short answer is that the code you show above is safe as long as you are not moving nodes around in the scenes stack. There are many alternative ways for individual nodes to learn about the "graph" of your game, including the parent
property of every CCNode
, and the runningScene
property of the CCDirector
.
Upvotes: 0