Overriding CCNode setPosition resulting in strange results - cocos2d-iphone

I'm having trouble wrapping my head around this problem with the setPosition of my CCNode subclass "Unit".
The subclass has a CCSprite property and a CCProgressTimer property. I want it to behave so that when I call Unit setPosition, it would move my sprite and my progressTimer to that position with an offset.
- (void) setPosition:(CGPoint)position
{
[super setPosition:position];
self.health_bar.position = ccpAdd(position, ccp(0,-10));
self.sprite.position = ccpAdd(position, ccp(0,10));
}
What actually happens is that the progress bar gets moved to where I want it to, but the sprite is moved more and more away as you set the position further away from (0,0).

Needed to convertToNodePosition

Related

CCNode in Cocos2d-x?

In cocos2d-iPhone we have a CCNode which:
has a position
has a size (wether we like it or not, it has)
an anchor point
This is very useful to define areas on screen where that area has children that belong together. Like a group of buttons. We can easily hide/unhide everything just by hiding that parent CCNode.
What is the equivalent in cocos2d-x? I see that Node does not have a size. Layer seems like its going to be deprecated... and according to the docs, a Sprite is something that moves. Where is the logical stuff?
Implement that function by yourself:
void setVisibilityWithChildren(CCNode* parent, bool bVisible) {
if (0 == parent) return;
CCNode* node = NULL;
CCARRAY_FOREACH(parent->getChildren(), node)
{
setVisibilityWithChildren(node, bVisible);
if (node) node->setVisible(bVisible);
}
}
In cocos2d-x, CCNode has the same attributes as it in cocos2d. Including size, position, anchor point and so on.
I don't know what it like in cocos2d, but in cocos2d-x CCNode is something without graph. You may consider that it is invisible.
If you wish to see where and what the size it is. You may use CCLayerColor instead. All of the functions you use are the same as CCNode, besides an extra step setColor()
CCNode => CCLayer => CCLayerRGBA => CCLayerColor (this is the inheritance tree of CCLayerColor in cocos2d-x 2.2.6)

Trouble removing sprites from parent node

I'm making an endless running game in which users dodge obstacles, and I'm working on producing the obstacles right now. The plan I had where I'm spawning these obstacles is as follows:
obstacle->setPosition(CCPointMake(this->getContentSize().width, this->getContentSize().height*.75));
obstacle->setScale(.5);
this->addChild(obstacle);
_obstacles->addObject(obstacle);
obstacle->runAction(CCMoveBy::create(2.0, CCPointMake(-(this->getContentSize().width + obstacle->getContentSize().width/2), 0)));
obstacle->removeFromParent();
I set the position, set it's scale, add it to the scene, run an action on it so that it moves across the screen from right to left, add it to an array called _obstacles to be used elsewhere, and then I remove it from the scene so as to save memory. However, the problem is that once I try implement this, the obstacle doesn't show up at all as if it's nowhere to be seen. When I don't call obstacle->removeFromParent() it shows up and performs the action. What am I doing wrong here? If I don't call removeFromParent(), what do I call? Is there a problem in my code not related to removeFromParent()?
The reason that obstacle doesn't apeear at all is that it is removed as it start moving. You just have to create a sequence of move action and function call with obstacle as parameter and than remove this obstacle in that function , so that obstacle will be removed after moving out of screen.
CCCallFuncN *myCallFunc = CCCallFuncN::create(this, callfuncN_selector(CLASS_NAME::removeObstacles));
obstacle->runAction(CCSequence::create(CCMoveBy::create(2.0, CCPointMake(-(this->getContentSize().width + obstacle->getContentSize().width/2), 0)),myCallFunc,NULL));
Method to remove obstacle from array and from parent view
void CLASS_NAME::removeObstacles(CCObject* pSender){
// Type cast pSender to obstacle type e.g if obstacle is of CCSprite type.
CCSprite *tempObstacle = (CCSprite *)pSender;
_obstacle.pop_back(tempObstacle);
tempObstacle->removeFromParent();
}
Don't forget to replace CLASS_NAME by your class name
I would need more info on what removeFromParent is doing and how you use _obstacles
I'm taking a guess on how the parent is structured. I would guess that it has a list of children and when the parent is updated/render, it calls those functions for its children. If removeFromParent removes the object from its parent list, then that would explain why it is not being render or used in the scene. If you have a setup like this, then you should only call removeFromParent before destroying the parent object

Cocos2d: the best way to compose an object that will contain several Sprites

I need to create an object that contains several sprites (2 for simplicity: the game object and its' shadow).
I need to compose them into the same class, so having the following questions:
what is the best ancestor class to the described one?
I used CCNode for this purpose. I overridden its draw method in the following way:
- (void)draw {
[super draw];
[_item draw];
[_itemShadow draw];
}
and suddenly found that need to change all other CCNode methods in the same way. For ex. change position, visible, etc. in order to change these properties in both Sprites my custom container aggregates:
#interface NBChecker : CCNode {
CCSprite *_item;
CCSprite *_itemShadow;
}
#end
There is the other way I see - to make both sprites parent property pointing to self. This should synchronise positions, visibility, etc. for these sprites.
Who has better ideas?
Would like to use aggregation and not sure I'm right in my thoughts.
Thanks!
Scrap the draw code. All you need to do is to add the two sprites as children of the CCNode subclass. Write your logic code in the CCNode subclass and have two ivars for each sprite for easier access (like you already have).
You don't need to draw the sprites yourself as long as they are part of the scene graph.
The sprites will move and rotate relative to their parent automatically. Move the node to move the sprites in unison, etc.

Cocos2d - removeChild by location

I have a number on CCSprites on screen which have CCNodes placed upon them, and added as children. How can I remove the CCNode child based on touch location (or touched sprite location)?
I have attempted creating a custom method (see below) but am unsure how to fill it in.
-(void)removeChild:(CCNode*)node location:(CGPoint)location cleanup:(BOOL)cleanup;
Is it possible to specify location with the built in method?
[self removeChild:(CCNode *)[node at location] cleanup:(BOOL)cleanup]
You can get local rect of your sprite by sending boundingBox message. Then just test your touch position with CGRectContainsPoint function. The only thing you should remember, that you need convert your coordinates(for example, if your sprites are children of some node, then their rects will be relative to it's (0.f, 0.f) coordinate, not to the scene (0.f, 0.f)). Also you should convert your touch location with sending convertToGL: message to CCDirector shared instance.

Game object with composition and CCSpriteBatchNode

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.
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.