How do you detect if an action is already running ?

Forums Programming cocos2d support (graphics engine) How do you detect if an action is already running ?

This topic contains 33 replies, has 5 voices, and was last updated by  leocck 3 years, 7 months ago.

Viewing 25 posts - 1 through 25 (of 34 total)
Author Posts
Author Posts
September 1, 2010 at 11:24 am #224444

EasyDev
Participant
@easydev

Hi…

All my question is in the title. I would want how to detect running actions on a CCSprite to do some conditions with that stuff. Is it possible ? I tried this :

if (CGRectIntersectsRect([perso boundingBox], [chaussure boundingBox]) && (![chaussure isRunning])) {}

But I wanted to know if it was possible to detect if the CCSprite (chaussure) was running a specific action.

Thanks in advance,

Best regards

September 1, 2010 at 12:31 pm #296531

chrisco
Participant
@chrisco

If you keep a reference to the action you want to check on, you could call:

BOOL isActionDone = [anAction isDone];

If you don’t want to keep a reference, tag your action when you create it:

CCAction *action = [CCAction action];
action.tag = kActionTag; // a constant, could use any int

Then later on, you could check the node for running actions:

if ([node numberOfRunningActions] > 0) {
CCAction *action = [node getActionByTag:kActionTag];
if (nil != action) {
BOOL isActionDone = [action isDone];
}
}

However, I’m not sure that will tell you if the action was actually running at the time, only if it’s done. Just because it’s not done doesn’t mean it’s actually running as it may be waiting in the queue (for example, if it’s placed in a CCSequence after a CCDelayTime).

September 1, 2010 at 1:16 pm #296532

EasyDev
Participant
@easydev

Thanks a lot for this very helpful post !

So, I just created my actions before the implementation of my class, as that :

id actionFadingRougeLevres;
id actionScalingRougeLevres;
id bothActionsRougeLevres;
id actionMoveDoneRougeLevres;

And in the init method, I init them :

actionFadingRougeLevres = [CCFadeOut actionWithDuration:durationFading];
actionScalingRougeLevres = [CCScaleBy actionWithDuration:durationScaling scale:scalingMod];
bothActionsRougeLevres = [CCSpawn actions:actionFadingRougeLevres, actionScalingRougeLevres, nil];
actionMoveDoneRougeLevres = [CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)];

But when I launch my code without modifying everything else, my app crashes on the GamePlay view. I’m a bit confused. Did I do something wrong ?

Thanks in advance for your help, chrisco !

September 1, 2010 at 1:46 pm #296533

Zhenmuron
Participant
@zhenmuron

What error do you get? Also if you want to call an action later in the program i believe you have to retain them, ex.

actionFadingRougeLevres = [[CCFadeOut actionWithDuration:durationFading] retain];

Then just

[object runAction: actionFadingRougeLevres];

Then remember to release them in the dealloc

September 1, 2010 at 2:00 pm #296534

chrisco
Participant
@chrisco

@Zhenmuron‘s right – you need to retain the actions. But if you don’t need to run the first two actions separately (actionFadingRougeLevres & actionScalingRougeLevres), you only need to retain bothActionsRougeLevres. That action will maintain a reference for the previous two.

September 1, 2010 at 2:49 pm #296535

EasyDev
Participant
@easydev

Thanks a lot for your help, but I tried with this method and it’s very complicated to put that all stuff in work. So, is it possible to tell to a CCSprite to run nothing else action when this CCSprite is running a specific action ?

EDIT : Everytime I ask this question there is no answers.

September 1, 2010 at 4:55 pm #296536

EasyDev
Participant
@easydev

<img<

September 1, 2010 at 5:04 pm #296537

cjl
Participant
@cjl

Why not just set a flag when the action is running, and unset the flag when the action completes? Then you can check to see if the flag is set before running another action. Or, maybe I’m misunderstanding your question?

September 1, 2010 at 5:10 pm #296538

EasyDev
Participant
@easydev

You understood perfectly my problem, but I can’t do this because (I don’t know why ?) the code above doesn’t work. Could you guide me ?

To help you guiding me, I’ll tell you more about my game. I have a tick method who is always verifying for a collision between objects and the character or collisions between objects and enemies. When the collision happens between the character and the object, the object run an action. The problem is that if my character touches first the object, then the enemy can still touch the object and the object will run the same action as when he intersects with the character. So the action will be runned while it’s already running. I want my object to do not run the action if it’s already running. Could you help me to prevent that ?

Thanks a lot for your help :)

September 1, 2010 at 6:12 pm #296539

cjl
Participant
@cjl

Create a CCSequence, and have the final action in the sequence call a method that changes a global variable (the flag). Check that variable before running a new action.

September 1, 2010 at 6:14 pm #296540

EasyDev
Participant
@easydev

What’s a flag ? Could you please give me a detailed example with some code ?

September 1, 2010 at 7:06 pm #296541

cjl
Participant
@cjl

A flag is a variable, use can use a BOOL if you want to, something like:

BOOL isRunning = NO;

Then have your CCSequence call a method that toggles the flag when the action starts or finishes. Search this forum, there are plenty of detailed examples.

September 2, 2010 at 9:39 am #296542

EasyDev
Participant
@easydev

Okey, I tried what you told me. Here is it :

if (canLaunchTheAnimation) {
if (CGRectIntersectsRect([perso boundingBox], [parfum boundingBox])) {

score = score+40;
// Unlock le succès SMELLS GOOD
[OFAchievementService unlockAchievement:SMELLS_GOOD__];
// Lance le fondu
[parfum runAction:[CCSequence actions:actionPeutPasLancer,bothActions, actionMoveDone,actionPeutLancer, nil]];
}
}

The problem is that the CGRectIntersect is called each time the character touches the object. And so first the BOOL canLaunchTheAnimation is equal to YES. Then, the character touches the object and the BOOL becomes NO. Then if the character stays on the object it will relaucnh the action of CGRectIntersect, and it will not be able to finish the animation and even less able to put canLaunchTheAnimation to YES because canLaunchTheAnimation will be equal to NO and so the runAction method will not be called because of the condition

if (canLaunchTheAnimation) {

. I hope you understood this ?

So I know where do my problem come from, it’s because of the CGRectIntersect method. Is it possible to tell to my CGRectIntersect method to be executed just one time, just at the first contact between the character and the object (in this case, parfum) ? Thanks in advance for your help !

September 3, 2010 at 9:52 am #296543

EasyDev
Participant
@easydev

up.

September 3, 2010 at 8:12 pm #296544

EasyDev
Participant
@easydev

Thanks a lot for this help cocos2d community. I think that you don’t even realize how it’s difficult for me to speak english.

September 4, 2010 at 1:44 am #296545

leocck
Participant
@leocck

Hi EasyDev

I think you can do something like that:

1- Initialize your flag with NO value when needed

canLaunchTheAnimation = YES;

2- Reset your flag when user interacts with your app

if (canLaunchTheAnimation) {
if (CGRectIntersectsRect([perso boundingBox], [parfum boundingBox])) {
// reset the flag so the user can't launch the animation anymore
canLaunchTheAnimation = NO;
// do what you like now
score = score+40;
// Unlock le succès SMELLS GOOD
[OFAchievementService unlockAchievement:SMELLS_GOOD__];
// Lance le fondu
[parfum runAction:[CCSequence actions:actionPeutPasLancer,bothActions, actionMoveDone,actionPeutLancer, nil]];
}
}

September 4, 2010 at 11:33 am #296546

EasyDev
Participant
@easydev

Thanks a lot leock, but it malherously doesn’t work… I don’t know why, it should work perfectly, but it doesn’t ! With this code I can’t never collide with any object… And the ennemy can’t either… Perhaps it comes from my method ? I saw with some NSLogs that the canLaunchAnimation BOOL was at the first on YES, but after, it becomes NO, and it stay NO.

Here is the code :

// PARFUM PERSO
if (peutCollideAnim) {
if (CGRectIntersectsRect([perso boundingBox], [parfum boundingBox])) {
// reset the flag so the user can't launch the animation anymore
peutCollideAnim = NO;
// Incrémente le score
score = score+40;
// Unlock le succès SMELLS GOOD
[OFAchievementService unlockAchievement:SMELLS_GOOD__];
// Lance le fondu
[parfum runAction:[CCSequence actions:bothActions, actionMoveDone,actionPeutLancer, nil]];
}

}

Here is the actionPeutLancer declaration :

actionPeutLancer = [[CCCallFunc actionWithTarget:self selector:@selector(autorisationLancerAnim:)] retain];

And here the method called by actionPeutLancer :

-(void)autorisationLancerAnim:(id)sender {

peutCollideAnim = YES;
NSLog(@"peutcollideanim = YES");

}

September 4, 2010 at 2:30 pm #296547

leocck
Participant
@leocck

I think I know what’s wrong, please test this: where you call the actionPeutLancer to run, replace the code for simply

peutCollideAnim = YES;

I think your action is running only one time, to run actions twice you need to ‘reset’ them.

But you don’t need necessarily an action to simply call a function, you can call it directly.

September 4, 2010 at 9:53 pm #296548

EasyDev
Participant
@easydev

Thanks Leocck, but I didn’t understood what you tried to explain me, sorry. My code has already the form :

peutCollideAnim = YES;

What have I to change ? Thanks a lot for your help, I really appreciate people who spend time for helping others :)

September 5, 2010 at 4:45 am #296549

leocck
Participant
@leocck

Where are you starting the running action? (It’s something like [self runAction:actionPeutLancer] )

I was trying to say that you don’t need an action to simply call a function. You could call autorisationLancerAnim instead, or even set the peutCollideAnim flag to YES value directly.

September 5, 2010 at 11:04 am #296550

EasyDev
Participant
@easydev

Thanks for this information, very helpful ! So I tried this :

if (peutCollideAnim==YES) {
if (CGRectIntersectsRect([soucoupe boundingBox], [sac boundingBox])) {
NSLog(@"sac/soucoupe");
// reset the flag so the user can't launch the animation anymore
peutCollideAnim = NO;
// Lance le fondu
[sac runAction:[CCSequence actions:bothActions, actionMoveDone, peutCollideAnim=YES, nil]];
}
}

But malherously when I launch the app, it crashes without telling me why. I’m a bit confused now.

September 5, 2010 at 1:21 pm #296551

leocck
Participant
@leocck

So I think you could post your full class source code for us to see.

Please use pastebin.com, I’ve started a code in http://pastebin.com/bkjQgN6Z for you to post.

Regards

September 5, 2010 at 2:08 pm #296552

EasyDev
Participant
@easydev

Done ! I hope you understand french, because comments are in french, hehe ! Thanks a lot for the time you pass trying to help me !

September 5, 2010 at 9:32 pm #296553

leocck
Participant
@leocck

Hi EasyDev,

Looking at your code I saw you was misunderstanding what I’ve trying to ask you.

I’ve changed your code a little bit, but since I don’t have the entire project could you please test it and tell me what exactly happens?

http://pastebin.com/34e2FKSF

(Don’t forget to put the link so I can find your code – the updates create a new link)

I was looking at your dealloc function… First you change your references to NULL and after that you release them, shouln’t be the other way around? Is this working for you?

September 6, 2010 at 2:22 pm #296554

EasyDev
Participant
@easydev

Hi, thanks a lot, the code works now, but the bool value still stays to NO with the NSLogs. When the “soucoupe” sprite collide with an object, the bool value becomes no and it stays no during all the time. I don’t really understand why… Looks like the bool value don’t become YES after because the action who’s supposed to put the bool on YES isn’t called correctly, but I don’t know why.

Viewing 25 posts - 1 through 25 (of 34 total)

You must be logged in to reply to this topic.