Cocos2d - Actions and Animations are not paused - cocos2d-iphone

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.

Related

how to properly handle touch events for multiple layers?

I currently have a "Console" CClayer, which is handling touch detection for sprites that have been added to it. However, I also have some sprites that I want to do touch detection on that are not part of the Console layer... They are currently children of a class that inherits from CCNode.
My understanding is, the more cocos objects have the "isTouchEnabled" property set to true, the more performance will be affected, so I am curious how I should approach this?
Should I:
A) Have the console's touchesBegan method perform detection of the sprites belonging to the CCNode?
B) Just implement isTouchEnabled on the CCNode object
C) Some other approach?
well, for starters, you should only concern yourself about performance if you are concerned i.e. you are seeing or measuring (on DEVICES not a simulator) some inappropriate response times.
I would avoid detecting touches that concern another node - it could get messy, software wise. I tend to return YES (from a ccTouchBegan) strictly when the touch is at a location of an object of concern to the detecting node. When you return NO, the dispatcher will pass on the touch to other handlers ('under' the console), until one such CCNode takes the bite. Kind of as follows:
- (void) onEnter{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
[super onEnter];
}
- (void) onExit{
[[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self];
[super onExit];
}
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
if (!_visible || !_enabled) {
return NO;
}
CGPoint loc = [touch locationInView:touch.view];
loc = [[CCDirector sharedDirector] convertToGL:loc];
if ([self containsPoint:loc]) {
// do your thing here !
return YES;
}
return NO;
}
-(BOOL) containsPoint:(CGPoint) location {
// determine here whether this node should be handling
// this touch.
}

cocos2d scene retaining issue

There is a scene in my application which has only two labels and a menu item. When I load this scene using replaceScene method it stays for 3-4 seconds and then gets disappeared or released. I want to keep it until cancel button is pressed. How can I do it? code is:
#implementation MyLayer
+ (id)myScene {
CCScene *aScene = [CCScene node];
MYLayer *myLayer = [MyLayer node];
[aScene addChild:myLayer];
return aScene;
}
- (id) init {
if (self = [super init]) {
//labels and menu here
}
return self;
}
And I am calling it from another scene like this:
[[CCDirector sharedDirector] replaceScene: [MyLayer myScene]];
Maybe the problem is that it's your first scene. Then you should use runWithScene method of CCDirector.
did you try replacing that scene with a "empty" init function to see if it still releases itself? It might be because of the amount of textures you are putting into memory
I did have sort of similar problems before because the images used in the new scene is too big and got auto purged by my app delegate, thus returning me an empty scene sometimes

Cocos2D removeChildByTag

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);
}

Cocos2d: Preloading animation causes a crash

I am trying to preload an animation in the init method of my layer. I then call the animation if the screen is touched. The app crashes with no error message as soon as I touch the screen and seems it is to do with calling the preloaded animation. I would like to do it this way as it seems expensive to create the animation every time the screen is touched - which does seems to work though. Any tips greatly appreciated.
Sample Code:
In my header:
#interface Test : CCLayer {
NSMutableArray *wake;
CCSprite* ani;
CCAnimate *animate;
}
#end
In my implementation:
-(id) init {
if( (self=[super init])) {
// enable touches
self.isTouchEnabled = YES;
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"ani.plist" texture:[[CCTexture2D alloc] initWithImage:[UIImage imageNamed:#"ani.png"]]];
ani = [CCSprite spriteWithSpriteFrameName:#"ani1.png"]; //comes from .plist file
ani.anchorPoint=ccp(0,0);
ani.position = ccp(700,65);
[self addChild:ani z:30];
wake = [NSMutableArray array];
for(int i = 1; i <= 4; i++) {
[wake addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"ani%d.png",i]]];
}
animate = [CCAnimate actionWithAnimation:[CCAnimation animationWithFrames:wake delay:1.0f] restoreOriginalFrame:FALSE];
}
return self;
}
Handling the touch:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// run the animation
[ani runAction:animate];
}
Animations in Cocos2d are not designed to be reused. You need to create a new one every time.
Problem solved by creating properties for the array and animation on the class using nonatomic,retain.
You only need to retain the animation but the array can be local.
self.myAnimation = [[CCAnimation animationWithFrames:myAniFramesArray delay:0.1f] retain];
Remember to make the property nonatomic, retain as stated by Chev and to release any objects you retain in the appropriate dealloc method.

Cocos2d - Changing animations after one is over

I've got a CCSprite with three animations: idle, walk and attack. I want to switch between idle and walk depending on whether or not the sprite is moving (if the joystick is beeing used). All of this works great.
For the attacking animation, I want it to run once, and then return to the previous animation when done (ex.: idle) how do I detect when the animation is done?
thanks,
Dave
Alright, so here's what i've done, and it works, although I have no clue if its the right or the best way:
1) store the current animation.
2) If the currentAnimation is attacking, do nothing.
3) when switching between animations, if the new animation is attacking, run a sequence on the sprite, the second action being a callback to a "onDoneAttacking"
4) in the callback, change the current animation
But this isn't veery smooth and it doesn't allow to attack very fast.
Here's what it looks like:
-(void) changeAnimation:(NSString*)name forTime:(int) times {
if(currentAnimation != #"attack" )
{
CCFiniteTimeAction *action = [CCAnimate actionWithAnimation:[self animationByName:name]];
CCRepeat *repeatAction = [CCRepeat actionWithAction:action times:1];
if(name == #"attack") {
id doneAttacking = [CCCallFunc actionWithTarget:self selector:#selector(onDoneAttacking)];
[self runAction:[CCSequence actionOne:repeatAction two:doneAttacking]];
}
else {
[self runAction:repeatAction];
}
currentAnimation = name;
}
}
-(void) onDoneAttacking {
currentAnimation = #"idle";
}