I'm using Cocos2d to write game for iPhone.
Here's the problem.
I have CCSprite and CCAction which is run on it.
CCSprite texture;
CCAction anim_action;
"Anim_action" is a CCRepeatForever action.
Now I want to check if this animation is running.
First I though I can use [isDone] function, but I think it doesn't work on CCRepatForever actions (I'm not sure - this opion is based on my tests)
So how to check if this animation is already running on my "texture"?
Maybe there is a way to get name of action which is running on texture at the moment?
It may be also useful!
There is a way to check if a specific action runs on your texture. Use:
CCAction *action = [texture getActionByTag:kAsignedActionTag];
where kAsignedActionTag is the tag assigned to the your animation.
anim_action.tag = kAsignedActionTag;
If your action is still running the getActionByTag method will not return nil.
I don't believe there's a way to directly tell if a CCRepeatForever action has completed since the isDone would make no sense, but there are some techniques you can use to essentially provide a callback to indicate if something is still running:
Override the step: method and call out to something that checks the interval - when it exceeds a threshold you can assume completion...kinda'
Wrap the inner action of the CCRepeatForever with a CCSequence. The first action of the sequence would be your repeated action and the second would be a CCCalFunc, again indicating that the action is still running
Subclass the CCRepeatForever and override the dealloc so you can fire a callback when the action is killed and released
You can easily use [isDone] while appling an effect
- (void)shakeThatThingOn: (BOOL)on { //you can return BOOL and get if the animation is working or not
if (on == YES){
id shaky2 = [CCShaky3D actionWithRange:3 shakeZ:NO grid:ccg(15,10) duration:5];
if (![shaky2 isDone])
[self runAction:[CCSequence actions:shaky2,[CCStopGrid action],nil]];
}
else {//this else is being called when you turn off animation (it's just 0.2s continuation after turning off - for better visual effect.
[self stopAllActions];
id shaky2 = [CCShaky3D actionWithRange:3 shakeZ:NO grid:ccg(15,10) duration:0.2];
[self runAction:[CCSequence actions:shaky2,[CCStopGrid action],nil]];
}}
and control it by simple BOOL if it's on or off.
I don't know if it's what you mean, but hope it'll help anyway.
If you know how many actions will be running on the sprite, or if the animation is the only action, then you can infer that the animation is running by checking the sprite's total number of running actions.
if ([texture numberOfRunningActions] > 0) //animation is running
or
if ([texture numberOfRunningActions] > someNumber) //if you had other actions running
Related
I'm using cocos2d and cocosBuilder.
I'm trying to do a starting animation, and then once it has finished, make all of the children nodes perform their idle animations.
how I'm doing the starting animation:
(void) onEnter
{
[super onEnter];
CCLOG(#"onEnter being called");
// Schedule a selector that is called every frame
[self schedule:#selector(update:)];
// Make sure touches are enabled
self.touchEnabled = YES;
//intro animation
CCBAnimationManager* animationManager = self.userObject;
animationManager.delegate = self;
[animationManager runAnimationsForSequenceNamed:#"words"];
}
and this is what my completedAnimationSequenceNamed looks like:
(void) completedAnimationSequenceNamed:(NSString *)name{
CCLOG(#"animation ended");
for(CCNode *c in [self children])
{
if([c isKindOfClass:[GameObject class]])
[c playIdleAnimation];
}
}
For some reason, my completedAnimationSequenceNamed is being called repeatedly, many times a second, causing my children to constantly restart their idle animations.
Any ideas?
I got it working, this is for anybody else running into this problem.
In order for the "(void) completedAnimationSequenceNamed:(NSString *)name" method to work properly you must have your animation start automatically (in the cocosBuilder project) instead of using running Animations from animationManager.
If I used the runAnimation method from animationManager, it (essentially) broke the callback method. But I just took that out and made the animation run automatically and it calledback as expected.
I am using Cocos2d 2.1rc0.
I have this project that was working perfectly when I was not using CCSpriteBatchNode. Then I decided to use batch nodes to reduce draw calls and my problems started.
A lot of stuff is not working well. reorderChild is one. Another one is runAction and without runAction Cocos is useless.
This is an example of a method that works without batchNodes and do not work with it.
// move/rotate all objects
for (int i=0; i<[allObjects count]; i++) {
Card *object = [allObjects objectAtIndex:i];
[object stopAllActions];
CGPoint center = object.position;
center.x = center.x + 100;
center.y = center.y - 200;
CCMoveTo *moveAction = [CCMoveTo actionWithDuration:0.3f position:ccp(center.x, center.y)];
CCRotateTo *rotateAction = [CCRotateTo actionWithDuration:0.3 angle:0.0f];
CCSpawn *action = [CCSpawn actions:moveAction, rotateAction, nil];
[object runAction:[CCSequence actions: action,
[CCDelayTime actionWithDuration:0.1f],
nil]];
}
Exactly nothing happens.
I have tried to eliminate the CCSpanw and use runAction directly just with move and nothing works. If I use regular sprites, it works.
Objects in that array derive from a CCSprite based class.
Is there any workaround?
the solution is to cast the class to the object extracted from the array...
instead of
Card *object = [allObjects objectAtIndex:i];
this
Card *object = (Card *)[allObjects objectAtIndex:i];
After double-checking in a clean project that this isn't a weird side-effect of some kind, I have to say there's something fishy about your project. Hard to tell what, though.
What I did: create a sprite-batch, add a sprite to it, also store it in an array. In a scheduled method I'm receiving the sprite from the array (not casting) and run your action sequence posted above. It works fine, as expected.
The casting should not make any difference. Batched or non-batched sprite should not make any difference either.
If it does, something really weird is going on. After all the card object is the same with or without casting. If it were not actually running the runAction method, you'd be receiving an "unrecognized selector sent to instance" error. But that's not the case.
Try again without casting, after rebooting your device, your machine, cleaning the project in Xcode and rebuilding. Also test in debug and release configurations. I've had the weirdest issues that were gone after doing one of the above, and definitely all of the above. If that doesn't fix things, you can be sure it's a problem with the code (memory leak is my alltime favorite) or the project settings (ie uncommon compiler optimizations sometimes can have side-effects).
Step into the runAction method if it really doesn't run the action - I'm sure it will add the action to the action manager. Try with and without casting to see if there really is a different code path taken. I doubt it.
My problem is this: i do quite a bit of code in ccTouchEnded and i want for the CCTouchDispacher to stop all input until all actions on the screen are over. The thing is that when i tap the screen repeatedly ccTouchEnded gets called every timeand it ruins everything. I've tried to stop the input but i don't know which of the actions will execute..so i can't just run a CCSequence and when it's finished re-enable input.
My code looks something like this:
if (taped in a rect)..do action, change some things around,do another action, call method 1
if (condition)..do action,check something,(if (check) do action, else call method 2)
Its worth noting that the methods do different things in different layers which take different amounts of time.
So my question is this: Is there any way to check if all actions on the screen are completed?
Check that the number of running actions on the node/sprite/layer is zero:
http://www.cocos2d-swift.org/docs/api/Classes/CCNode.html#//api/name/numberOfRunningActions
Such as:
[mySprite numberOfRunningActions]==0
You have the isDone function that tells you if an CCAction is finished. From the docs:
(BOOL) - isDone return YES if the action has finished
How to remove animation from object in raphael?
var animation = Raphael.animation({opacity:.2}, 1000);
var circle = paper.circle(0, 0, 5).animate(animation.repeat(Infinity));
I want to perform animation on object until some moment in time. And the question is how to remove/stop animation in that specific moment?
Well, I really don't know why, but the fiddle works if don't pass any arguments to the stop method. Despite what Raphael's documentation says, I found a working example of an animation stopping in this site (is not the most beatiful site, by the way, but they have an example for each raphael method!)
Here you have the Fiddle working. http://jsfiddle.net/fKxqS/2/
Enjoy!
If you want to stop the animation after a specific timelapse...
setTimeout(circle.stop(animation), 500) //500 is milliseconds, so it's 0.5s
If you want to stop the animation after an event, such as a click
circle.click(function(){
circle.stop(animation)
})
Edit: Seems Raphael doesn't stop if repeat is set to Infinite, perhaps somebody knows a workaround, here's the fiddle: http://jsfiddle.net/fKxqS/
I have a CCRepeatForever action with a tag of 20. I call this:
[player stopActionByTag:20];
Noting happens.
I call this:
[player stopAllActions];
It stops. Any idea? The action is created like this and runs fine:
CCRepeatForever *repeat=[CCRepeatForever actionWithAction:animate];
repeat.tag=20;
[player runAction:repeat];
update: i also tried setting animate.tag=21 and stopping that action by itself or in addition to the repeat action, but neither works.
This should work, I made a quick test with stopActionWithTag using CCRepeatForever and it stops it correctly.
I can only imagine two cases where it wouldn't work:
You have more than one action with the tag = 20 running on the same object.
The object you send runAction to is a different object than the one you send stopActionByTag to.
The former is easy to check. If this code fixes your problem, you're running multiple actions with the same tag on the player object:
while ([player getActionByTag:20]) {
[player stopActionByTag:20];
};
The latter is rather unlikely but possible. One way to find out is to set a breakpoint on the runAction line and note the address of the player variable. Then set another breakpoint at the stopActionByTag line and compare that player's address with the previous one. If they're not the same, then that would be the problem.