Game object with composition and CCSpriteBatchNode

一个人想着一个人 提交于 2019-12-13 01:35:10

问题


I'm currently developing a game with cocos2d and box2d on iPhone.
I read a lot of articles concerning game code organization, game objects structure etc. I first started developing my game objects by inheriting from a base class itself inheriting from CCSprite. I had a CCSpriteBatchNode to draw all the game items, which the player can interact with, in one draw call. This was easy because my Item class indirectly inherit from CCSprite so I could easily add my items to the CCSpriteBatchNode. And on top of that I could rely on cocos2d to retain my objects.

After I read the articles, I understood the need to refactor my code with a more composition oriented style rather than the inheritance style. So I went with a GameObject base class inherited from NSObject and having properties such as one or more CCSprite, one b2Body etc.

The problem I'm facing now is that I can't directly add my GameObject to the CCSpriteBatchNode anymore. I first thought I could easily fix the problem by adding the sprite property of the GameObject to the CCSpriteBatchNode. It's ok but who retains the object owning the CCSprite ? How can I easily access the original object from the CCSprite (are userData/Object ok) ?

Should I create an array retaining my items ? I'd like to know how you would use a CCSpriteBatchNode with such a game object structure ?

There is already a thread about that which is unanswered and I'd really like to hear about the subject. Not a straight answer but some elements to go further.

Thanks.


回答1:


Personally I don't recommend using NSObject as the base class for cocos2d classes anymore. Simply because you lose some cocos2d convenience features such as scheduling and you can easily shoot yourself in the foot, memory-management wise.

What you want is a setup where the scene has one or more sprite batch nodes. You can consider them layers for your sprites. Your actual game objects (consider them to be MVC controllers) deriving from CCNode can be added anywhere, typically directly to the scene.

scene
 + batch node 1
   + sprite 1
   + sprite 2
   + sprite n
 + batch node 2
   + sprite 1
   + sprite 2
   + sprite n
 + game node 1
 + game node 2
 + game node 3
 + game node n

The thing to keep in mind is that each game node has one or more sprites as instance variables, but they're not childs of the node. So for example the game node 1 class might look like this:

game node 1 class
  CCSprite* sprite1;  // instance variable
  CCSprite* sprite2;  // instance variable

Now when you init game node 1 and its sprites, you add the sprites to the appropriate sprite batch node. Typically you will want to access your scene like a singleton to get access to its sprite batch properties.

sprite1 = [CCSprite spriteWithSpriteFrameName:@"doodle.png"];
[[scene sharedScene].batchNode1 addChild:sprite1];
sprite2 = [CCSprite spriteWithSpriteFrameName:@"splash.png"];
[[scene sharedScene].batchNode2 addChild:sprite2];

Note that you do not need to retain the sprites as long as they are children of the sprite batch node. The addChild method retains it for you. Actually, it just adds it into an array which does the retaining. Also, if you're still thinking about "retain", by all means start using ARC.

You do not need to figure out how to access the sprite in the sprite batch. It's available as an instance variable of your game node class, and if you wish, you can also make it publicly available to other classes as a property.

The game node class obviously runs all the object's game logic, including positioning and otherwise modifying the sprite's properties. The only thing you need to take care of in the game node class is that you remove the sprites from the batch node, otherwise it may be leaking. To do so, override the cleanup method:

-(void) cleanup
{
    [sprite1 removeFromParentAndCleanup:YES];
    sprite1 = nil;
    [sprite2 removeFromParentAndCleanup:YES];
    sprite2 = nil;

    [super cleanup];
}

It's important to set the variables to nil because there may be code running after cleanup, including the code in the dealloc method. You could also remove the sprites in dealloc but depending on your setup, dealloc may not even get called because of the references to the sprite the game node class is still holding. Therefore it is generally safer to use the cleanup method if the sprites are not children (or grandchildren) of the game node class itself.



来源:https://stackoverflow.com/questions/10422081/game-object-with-composition-and-ccspritebatchnode

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!