I have a CCLayer which has multiple children (Sprites, CCMenuItemImages ets). And these children are having their children (mostly CCLabel*** or CCMenuItemImages). So I want to fade out the all the grand-children and children of the layer and then once all are faded I want to remove the CCLayer.
I am able to apply fade action to the hierarchy. But if I do [CCLayer removeFromParentWithCleanup:YES], then it removes immediately while still some children are running with fade action.
So my question is how can i remove the parent layer once all the gran-children and children are faded (opacity = 0).
Edit: Here is a code snippet
for(CCNode *node in itemLayer.children)
{
for(CCSprite *sprite in parentLayer.children)
{
for(id item in sprite.children)
[item runAction:[CCFadeTo actionWithDuration:2.5f opacity:0]];
[sprite runAction:[CCFadeTo actionWithDuration:2.5f opacity:0]];
}
}
itemLayer is the Parent CCLayer which has a CCNode *node. node is having children and each children have their children. So I want to remove the node and its parent itemLayer once all the actions completes on children and gran-children. How to do this?
Make your top level container a CCNodeRGBA and set in the init :
self.cascadeColorEnabled=YES;
self.cascadeOpacityEnabled=YES;
self.opacity=255;
When you run a CCFadeAction on that, the node will do all the forklifting of cascading down to children and grand-children. At the end of the fade action,
id fade = [CCFadeTo actionWithDuration:2.5 opacity:0];
id done = [CCCallBlock actionWithBlock:^{
[self removeFromParentAndCleanup:YES];
// plus whatever else you see fit
}];
id seq = [CCSequence actions:fade, done, nil];
[self runAction:seq];
ob cit : from memory, not compiled nor tested, YMMV
Related
Using cocos2d, I'm trying to replace a sprite (item in my code) with a particle system. This code is placed in my board class. This one works:
// Draw the particles
CCParticleSystem *particles = [[CCParticleSystem alloc] initWithDictionary:_popParticles];
particles.position = ccpSub(item.position,ccp(160,160));
particles.autoRemoveOnFinish = TRUE;
[self addChild:particles];
This one doesn't:
// Draw the particles
CCParticleSystem *particles = [[CCParticleSystem alloc] initWithDictionary:_popParticles];
particles.position = item.position;
particles.autoRemoveOnFinish = TRUE;
[self addChild:particles];
I tried player with this but without success:
particles.positionType = CCPositionTypeMake(CCPositionUnitUIPoints, CCPositionUnitUIPoints, CCPositionReferenceCornerBottomLeft);
My board is a 320x320 points CCSprite with anchor point set at 0.5, 0.5
When I log my item.position value, I get something relative to the bottom left corner of my board (from 30,30 to 290,290)
Is using ccpSub the correct way ?
When you destroy a node you also destroy all of it's children nodes, you said you add your particle to 'item' then you destroy that 'item', which means you have no particle anymore.
When I do this:
[gameLayer pauseSchedulerAndActions];
Most of the game pauses, but the sprites that are undergoing this action do not pause spinning:
[sprite runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:5.0 angle: 360]]];
Also, those sprites that are running CCAnimations do not stop animating:
CCAnimation *theAnim = [CCAnimation animationWithSpriteFrames:theFrames delay:0.1];
CCSprite *theOverlay = [CCSprite spriteWithSpriteFrameName:#"whatever.png"];
self.theAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:theAnim]];
How can I get these to pause when the game is paused? I would expect “pauseSchedulerAndActions” to pause actions, but that doesn’t seem to be the case.
pauseSchedulerAndActions is not recursive, so it will only affect actions and schedules on the node you are pausing, not it's children.
if your scene/layer is shallow, you could probably just get away with looping through the layer's children and calling (pause/resume)SchedulerAndActions on each, otherwise, if you have a deeper graph, you'll probably want to call it recursively. I wrote up a small test and this worked for me:
-(void) pauseSchedulerAndActions: (BOOL) pause forNodeTree:(id)parentNode shouldIncludeParentNode:(BOOL)includeParent
{
if(includeParent)
{
(pause) ? [parentNode pauseSchedulerAndActions] : [parentNode resumeSchedulerAndActions];
}
for( CCNode *cnode in [parentNode children] )
{
(pause) ? [cnode pauseSchedulerAndActions] : [cnode resumeSchedulerAndActions];
if(cnode.children.count > 0)
{
[self pauseSchedulerAndActions:pause forNodeTree:cnode shouldIncludeParentNode:NO]; // on recurse, don't process parent again
}
}
}
so in your case you could try calling this method and passing in your gameLayer
Try [[CCDirector sharedDirector] pause]; It should pause all animations and movements.
I need to put some CCsprites on screen that later on will be fade in to screen.
I cant hide them ,because the CCFade action will not work on hidden sprite , or a sprite with opacity=0 .
What i do is put them on screen and fade them out :
[colors[i] runAction:[CCFadeOut actionWithDuration:0]];
[self addChild:colors[i] z:0];
it turned out that fading out in zero time is not unseen, so they appear for a second the moment i add them to CCScene.
How would i put them on screen to be unseen, and than fade them in with CCFadeIn action ?
You can stack actions using a sequence. See the example below from one of my projects :
CCSprite *frame1 = [CCSprite spriteWithSpriteFrame:[frames objectAtIndex:0]];
frame1.flipX = self.flipX;
frame1.scale = self.scaling;
frame1.visible = NO;
frame1.opacity = 255;
frame1.rotation = self.rotation;
frame1.position = self.offset;
animation = [CCAnimation animationWithSpriteFrames:frames delay:(duration / self.numberOfFrames)];
id stall = [CCDelayTime actionWithDuration:delay];
id show = [CCShow action];
id animate = [CCAnimate actionWithAnimation:animation];
id hide = [CCHide action];
id clean = [CCCallBlock actionWithBlock:^{
[frame1 removeFromParentAndCleanup:YES];
}];
id enchiladas = [CCSequence actions:stall, show, animate, hide, clean, nil];
[node addChild:frame1 z:5];
[frame1 runAction:enchiladas];
Similar thing. I want to run an animation that will appear after a set delay time, then vanish and cleanup after itself when complete.
YOU can use sprite.opacity =0; initially
and in actions you can increase the opacity
I have a CCLayer class (yes, it has to be a CCLayer, not CCSprite) that has children CCSprites. I need to change the opacity and the scale of that layer, that in other words is I have to change the opacity and the scale of all children of that layer.
I learnt today that I can extend CClayer class, using this, to deal with the opacity of the children...
#import "CCLayer+Opaque.h"
#implementation CCLayer (CCLayer_Opaque)
// Set the opacity of all of our children that support it
-(void) setOpacity: (GLubyte) opacity
{
for( CCNode *node in [self children] )
{
if( [node conformsToProtocol:#protocol( CCRGBAProtocol)] )
{
[(id<CCRGBAProtocol>) node setOpacity: opacity];
}
}
}
- (GLubyte)opacity {
for (CCNode *node in [self children]) {
if ([node conformsToProtocol:#protocol(CCRGBAProtocol)]) {
return [(id<CCRGBAProtocol>)node opacity];
}
}
return 255;
}
#end
I did that and imported the file in my main class, but I still see this error when I try to set the opacity of that CCLayer: multiple methods named 'opacity' found
I also went beyond that and added this to the class extension:
-(void) setScale: (CGFloat) scale
{
for( CCNode *node in [self children] )
{
[node setScale: scale];
}
}
-(CGFloat) scale
{
for( CCNode *node in [self children] )
{
return [node scale];
}
return 1.0f;
}
To deal with the scale, using the same idea, but also see the message multiple methods named 'scale' found
In resume: how do I extend the CCLayer class to make all children of a CCLayer change scale or change opacity?
thanks
I discovered the problem. I had to cast the class to the CClayer object in order to read or set the opacity...
Example:
[(CCLayer*)obj setScale:0.5f];
Now it is working. Thanks.
I am making my first cocos2D game and i had trouble in tag. i gonna add many sprite to my gamelayer so i used [self addChild:sprite z:1 tag:aTag]; where aTag +=1; each time i increase the tag value. because each sprite should have a unique tag value. sometime i wanna clear all the child in my gamelayer so i remove those sprite by using the tag value like this.
for (int i=10; i<1000; i++) {
CCNode *child = [self getChildByTag:i];
if (child == nil)
NSLog(#"removeChildByTag: child not found!");
else{
NSLog(#"child removed");
[self removeChild:child cleanup:YES];
child=nil;
}
}
and when i add these sprite again like [self addChild:sprite z:1 tag:aTag] to my gamelayer there was error occured "EXE bad Access". why it show the error.
you can directly remove a child by using
[self removeChildByTag:aTag cleanup:YES];
as for the bad access, check if sprite is empty or if the image is empty
Use to define SAFE_REMOVE like this
#define SAFE_REMOVE(p) if (p) [p removeFromParentAndCleanup:YES];
// Remove the the tag
CCNode* node = [self getChildByTag:YOURTAGNAMEHERE];
if (node != nil)
{
SAFE_REMOVE(node);
}