How to transfer a CCSprite from one parent to another? - cocos2d-iphone

I have a CCSprite called sprite that is a child of a CCLayer called movingLayer that is itself a child of the current CCLayer running my game logic, so it is self in this case. movingLayer is moving back and forth across the screen in a repeat forever action and sprite is riding along on it. I want to get sprite to "get off" of movingLayer and "get on" to self where it can do some actions of its own.
When I try to do this, I need to tell movingLayer to remove sprite and self to add sprite. This is what I did...
- (void)attack:(id)sender
{
[sprite stopAllActions];
[movingLayer removeChild:sprite cleanup:YES];
[self addChild:sprite z:1];
CGFloat distance = ccpDistance(sprite.position, ccp(sprite.position.x, -sprite.contentSize.height/2));
id goDown = [CCMoveTo actionWithDuration:distance/moveDuration position:ccp(sprite.position.x, -sprite.contentSize.height/2)];
id repeatDown = [CCRepeatForever actionWithAction:[CCSequence actions:[CCMoveTo actionWithDuration:0 position:ccp(sprite.position.x, sprite.contentSize.height/2+self.contentSize.height)], [CCMoveTo actionWithDuration:moveDuration position:ccp(sprite.position.x, -sprite.contentSize.height/2)], nil]];
id attackAction = [CCSequence actions:goDown, repeatDown, nil];
[sprite runAction:attackAction];
}
I think stopAllActions is redundant, but that's not the problem. If I remove sprite from movingLayer before adding it to self I crash for accessing a zombie, and if I try to add it to self first, I crash for trying to add something already added.

Have you tried setting cleanup to NO?
Alternatively, try to retain sprite before you remove it from movingLayer, then release it when you're done with it:
[sprite retain];
[movingLayer removeChild:sprite cleanup:YES];
[self addChild:sprite z:1];
[sprite release];

Related

Cocos2d animation on sprite and detect contact on him

I know how to detect contact on all of my sprites that on screen .
I also know how to run animation forever on a sprite .
But when puting together the code for animation, with sprite sheet- you dont actually add the sprite as a child, but ONLY the sprite-sheet, than the sprite is a child of the sprite-sheet.
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"parrot.plist"];
CCSpriteBatchNode *spriteSheet = [ CCSpriteBatchNode batchNodeWithFile:#"parrot.png"];
fireBall=[CCSprite spriteWithSpriteFrameName:#"parrot1.png"];
fireBall.position=point;
[spriteSheet addChild:fireBall];
[self addChild:spriteSheet];
//here animation action perform on fireBall
In that case when looking for the fireBall for contact detection - you cant find him because he is not added as a child of the scene ,but of the sprite sheet.
How can i detect that sprite later on my code ? or there is another constellation to set the sprite sheet ?
thanks
You can get your fireBall sprite normally, like any other sprite...
There's some ways:
1) Create a property for your fireBall sprite:
#property (nonatomic, retain) CCSprite *fireBall;
And create and use it using self.fireball:
self.fireBall=[CCSprite spriteWithSpriteFrameName:#"parrot1.png"];
...
CGPoint fireBallPosition = self.fireBall.position;
2) Add fireBall as child on spriteSheet using tag, and get it back using the same tag.
[spriteSheet addChild:fireBall z:0 tag:1];
...
theFireBall = [spriteSheet getChildByTag:1];
But keep in mind that the fireBall position is relative of their parent, spriteSheet. So, if you move spriteSheet, you will also move spriteSheet.

How to animate something in the the VOID statement? XCODE

-(void) redafter1
{
red = [CCMenuItemImage
itemFromNormalImage:#"red.png" selectedImage:#"redclick.png"];
red.position = ccp(175, 725);
redMenu = [CCMenu menuWithItems:red, nil];
redMenu.position = CGPointZero;
redMenu.scale = .75;
[self addChild:redMenu z:10];
}
How would I go about animating this object to move to another location on the screen? I am very new to this, please be basic in your explanation.
If you want to animate CCNode (this is base class of all cocos2d objects such as layers, sprites, labels, menuitems, etc.), you have to use actions mechanism. To move object, use CCMoveTo, CCMoveBy actions with runAction: method.
id moveAction = [CCMoveTo actionWithDuration: animationDuration position: targetPosition];
[nodeToAnimate runAction: moveAction];
In your case if you will run action on the object right after adding it to the some parent, that is visible (your scene or other visible parent), action will be started right after object appear.
You add [redMenu runAction:[CCMoveTo actionWithDuration:time position:place]]; (you choose time and position) at the end of your redafter1 function so when the parent method is eventually called by a method such as init your menu will move.Remember you cannot move a CCMenuItemImage because it's locked to the CCMenu's position. You have to move the CCMenu itself.Hope this was helpful.

How to after recreate of same sprite, continue touch events

i have 2 layers and on ccTouchMoves event i have to destroy and recreate sprite to move from 1st layer to 2nd
i did this something like that
-(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
sprite = [CCSprite spriteWithFile:#"file.png"];
[[self parent] addChild: sprite]
if (sprite)
{
[sprite ccTouchBegan:touch withEvent:event];
// [character ccTouchMoved:touch withEvent:event];
}
[self removeFromParentAndCleanup:true];
}
sprite created and called method ccTouchBegan but after that method everything is terminate
how to call ccTouchMoved and ccTouchEnd just like simple touch event
If it's the same sprite, why destroy and recreate it? You can just keep on using the same sprite. In Kobold2D I added this method in a CCNode category to transfer ownership of a node from its current parent to a different parent:
-(void) transferToNode:(CCNode*)targetNode
{
CCNode* selfNode = [self retain];
[self removeFromParentAndCleanup:NO];
[targetNode addChild:selfNode z:selfNode.zOrder tag:selfNode.tag];
[selfNode release];
}
The important part is to remove the node (your sprite) from its current parent without cleaning up, so that schedulers and actions keep running. Then just add it as child to a different node (your 2nd layer).

CCAction in box2d world

i'm newbie to both cocos2d and box2d and i've been struggling for two days with this problem : i have a scene with many sprites dropping down (with bodies attached to them). and i have a BackgroundLayer from which i add my background image into the scene (which is not involded into the physics simulation). In my backgroundLayer i'm trying to perform an action on a sprite :
(it blink in the first position and jump directly to the end position )
id flyBubble = [CCEaseInOut actionWithAction:[CCMoveTo actionWithDuration:0.7 position:randomEndPosition]];
but my sprite doesn't respond at all to this action!! my sprite doesn't have any b2body attached and seems like it respond to the tick: method of the physics world (which is in my Main Scene). How can i perform an action to a sprite that doesn't have a b2body attached.
any help would be appreciated!!! thanks
here is the entire code :
CCSprite *bubble = [CCSprite spriteWithFile:#"bubble.png"];
[self addChild:bubble];
CGPoint startPosition = ccp(100, 100);
bubble.position = startPosition;
CGPoint endPosition = ccp(400, 400);
id flyBubble = [CCEaseInOut actionWithAction:[CCMoveTo actionWithDuration:0.7 position:randomEndPosition]];
id remove = [CCCallBlockN actionWithBlock:^(CCNode *node) {
[self removeFruit:(CCSprite *)node];
}];
[bubble runAction:[CCSequence actions:flyBubble, remove, nil]];
I guess source and destination position of sprite is same. So no difference in action.
try like this..
sprite.position = ccp(0,0);
id flyBubble = [CCMoveTo actionWithDuration:0.7 position:randomEndPosition];
[sprite runAction:flyBubble];
i did a little mistake that costs me lot of times. it was in this line of code
id flyBubble = [CCEaseInOut actionWithAction:[CCMoveTo actionWithDuration:0.7 position:randomEndPosition]];
CCEaseInOut doesn't work i don't know why!! when i used CCEaseExponentialInOut it worked perfectly.
Thanks anyway!

How to keep fps rate constant in cocos2d

I have 3 question.
How to keep fps rate constant(almost) in cocos2d.When lots of CCSprite created and removed within a small interval like (5-8) per second is it possible to keep frame rate lmost constant??
Is [self removeChild:sprite cleanup:YES] is enough or I should also use
CCTexture2D *texture = [sprite texture]; [[CCTextureCache sharedTextureCache] removeTexture: texture];
The following Part of code is responsible for my frame drop.How to accomplish same task in better way?
id fadeout = [CCFadeOut actionWithDuration:1.4f];
id call = [CCCallFunc actionWithTarget:self
selector:#selector(RemoveSmashedSprite:)];
CCSequence* sequence= [CCSequence
actions:fadeout, call, nil];
[smash runAction:sequence];
... and...
> -(void)RemoveSmashedSprite:(id)sender
{
CCSprite *sp = (CCSprite *)sender;
[self removeChild:sp cleanup:YES];
}
This is called 5-8 times per second. So the frame rate goes down. Can any one help me?
You shouldn't remove textures if you're going to reuse them in the short term. It would only benefit memory while having a great drawback in performance.
To maintain a constant frame rate you could try reusing the sprites instead of creating and removing them. Instead of calling removeChild you could set visible = NO and add it to an array of unused sprites. Then when you need a new of these sprites you check if there is any in that unused array and only create a new one if it's empty. This way you would minimize the amount of sprites created and destroyed.
Change this:
id call = [CCCallFunc actionWithTarget:self selector:#selector(RemoveSmashedSprite:)];
Into this:
id call = [CCCallFuncN actionWithTarget:self selector:#selector(RemoveSmashedSprite:)];
You can use remove action as your last action, instead of CCCallFunc.
id action = [CCActionRemove action];
This action will remove the node running this action from its parent