Check If animation is running in cocos2d-x - cocos2d-x

I am currently learning cocos2D-x and am doing some sprite animation.
My Objective is that when a button is clicked the object moves to left with some animation.
Now if you click multiple times rapidly the animation takes place immediately and it looks like the bear is hoping instead of walking.
The solution to it looks simple that I should check if animation is already running and if running the new animation should not take place.
The following is a part of my code.
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("AnimBear.plist");
CCSpriteBatchNode* spriteBatchNode = CCSpriteBatchNode::create("AnimBear.png", 8);
this->addChild(spriteBatchNode,10);
CCArray *tempArray = new CCArray();
char buffer[15];
for (int i = 1; i <= 8 ; i++)
{
sprintf(buffer,"bear%i.png", i);
tempArray->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(buffer));
}
CCAnimation *bearWalkingAnimation = CCAnimation::create(tempArray,0.1f);
startAnimation = CCSprite::createWithSpriteFrameName("bear1.png");
startAnimation->setPosition(ccp (350 , CCDirector::sharedDirector()->getWinSize().height/2 -100));
startAnimation->setScale(0.5f);
startAnimation->setTag(5);
//Animation for bear walking
bearAnimate = CCAnimate::create(bearWalkingAnimation);
Here bearAnimate is a global variable and i wish to know if its currently playing the animation.
How do I do it.?Thank you.

Assume the Sprite that runs the action is
CCSprite* bear;
I think you can use something like
bear->numberOfRunningActions()
numberOfRunningActions( ) returns an unsigned integer, so to check if there are no actions, you would have to check if it returns 0
if ( bear -> numberOfRunningActions( ) == 0 ) {
CCLOG( "No actions running." );
} else {
CCLOG( "Actions running." );
}

The bearAnimate (CCAnimate) has a method to check that.
if (bearAnimate.isDone())
doWhatYouWant();
The method is inherited from CCAction. Good luck.

Related

Few basics in cocos2d-x v3 Windows

I have some basic questions about some Problems in cocos2d-x v3.
1.) when I create sprites like that:
cocos2d::Sprite *sprite1 = cocos2d::Sprite::create("test.png");
auto sprite2 = cocos2d::Sprite::create("test.png");
How I have to to erease them proplery? Should I use autorelease (it crashes when I use it after create it)? Can I for both variants just use:
sprite1->removeFromParentAndCleanup(true);
sprite2->removeFromParentAndCleanup(true);
2.) When I want an Animation have active in my HelloWorldScene, so that i can use it when i want, how can I do it? I tried something like that:
void HelloWorld::runAnimationWalk() {
auto spritebatch = cocos2d::SpriteBatchNode::create("robo.png");
auto cache = cocos2d::SpriteFrameCache::getInstance();
cache->addSpriteFramesWithFile("robo.plist");
//spritebatch->addChild(worker);
Vector<SpriteFrame *> animFrames(5);
char str[100] = {0};
for(int i = 1; i <= 5; i++)
{
sprintf(str, "robot%i.png", i);
cocos2d::SpriteFrame* frame = cache->getSpriteFrameByName( str );
animFrames.pushBack(frame);
}
auto animWalk = cocos2d::Animation::createWithSpriteFrames(animFrames, 0.1f);
vector<Worker>::iterator it = workerVector.begin();
for(int k = 0; k<workerVector.size();k++) {
if(it->getType() == 1)
it->getWorker()->runAction(RepeatForever::create(Animate::create(animWalk)));
it++;
}
}
That works, but i have to call the function always after I want to change the animation. I tried to save the spritebatch, cache etc... global, but the animation dissaperars after a few time.
Answer 1) Yes. This is a full scenario:
//Create
Sprite *sprite1 = cocos2d::Sprite::create("test.png");
this->addChild(sprite1);
// Deleter Later
sprite1->removeFromParent();
Answer 2) You can create an animation ( Animation* ) and run it on any sprite.
some note:
If you want the animation play again and again, you can make a infinite version of your animation with RepeatForever::create(YourAnimation).
If you want to create the animation but use(display) it later. you can create your Animation* and retain() it until you run it on some target(sprite). (don't forget ro release it when running on target)

Libgdx: Pause between one cycle of animation

I have animation with 5 frames. I want to make pause for x seconds every time one animation cycle ends
1,2,3,4,5 (pause) 1,2,3,4,5 (pause) ...
Array<AtlasRegion> regions = atlas.findRegions("coin");
animGoldCoin = new Animation(1.0f / 20.0f, regions, PlayMode.LOOP);
I can't find way to do this.
Thanks
I don't really like the animation class, you can make your own.
float pauseTime=5f; // lets say that you want to pause your animation for x seconds after each cicle
float stateTime=0f; // this variable will keep the time, is our timer
float frameTime=1/20f; //amount of time from frame to frame
int frame=0; // your frame index
boolean waiting=false; // where this is true, you wait for that x seconds to pass
void Update()
{
stateTime+=Gdx.graphics.getDeltaTime();
if(!waiting && stateTime>frameTime) // that frame time passed
{
stateTime=0f; // reset our 'timer'
frame++; // increment the frame
}
if(waiting && stateTime>=0)
{
frame=0;
waiting=false;
}
if(frame>=NUMBER_OF_FRAMES)
{
frame--;
waiting=true;
stateTime=-pauseTime;
}
}
}
I think this will work, do you understand what I did?
I just had a similar problem but managed to come up with a solution. It works well for me but may not be the best way to go about it.. I'm still learning.
I created a new animation from the old animation's frames but with a speed of 0. It stops on the frame its at until the player speed changes.
if(speedX == 0f && speedY == 0f){
playerIdle = new Animation(0f,playerAnim.getKeyFrames());
playerAnim = playerIdle;
}
I know its an old question, but hopefully this will be useful to someone.
I made a quick solution in my search to pause a Libgdx animation.
I wanted an animation to pause when I pressed the spacebar.
I did try the above method of instantiating a new object and it did work. So I tried to just set the frame duration to 0, but that didn't work for some reason. This a less expensive method w/o instantiation.
If you want to pause an animation simply create three variables two are Boolean variables named toStop and hasLaunched another is a TextureRegion named launchFrame. Haslaunched is used to tell me when the spacebar is pressed.
if (InputHandler.hasLaunched && toStop ) {
launchFrame = launchBarAnimation.getKeyFrame(runTime);
toStop = false;
} else if (InputHandler.hasLaunched && !toStop){
batcher.draw(launchFrame, 90, 20, 50, 37);
} else {
batcher.draw(launchBarAnimation.getKeyFrame(runTime), 90, 20, 50, 37);
}

function 'for - do - end" / moving object ( Corona Sdk )

I'm beginner for coding, I've questions :
First I'd like know why that code is not moving :
local speed = 5
function cube ()
for i = 1,20,2 do
local rect = display.newRect(50,50,50,50)
rect.x = screenleft-300 + (50*i)
rect.y = _y
rect.x = rect.x - speed
if (rect.x < -450 )then
rect.x = 1200
end
end
end
timer.performWithDelay(1, cube, -1)
Secondly : What's the difference between
Runtime:addEventListener( "enterFrame", cube )
and
timer.performWithDelay(1, cube, -1)
Because I get the same result with both of them
And to be done, Why when I use the function "for" to duplicate something like the square i've done upside, this one put the image behind eachother and not like the square beside eachother ( the image i'm trying to duplicate has more than 4 side )
Thanks for all your reply !
thks a lot dude , I know what you mean by here but my question is little bit weird maybe lol and maybe we can't do it
I try to explain again :
for i=1,10,1 do
local Circle = display.newCircle(50, 20, 20)
Circle.x = _x + (50*i)
Circle.y = _y
end
So here I've a Circle line like that 00000 (imagine 0 are circle ^^)
and I want to make that line moving from the left to the right screen, but when i try to make it move with :
Circle.x = Circle.x - speed
Corona don't recognize the " circle.x " so I can't, maybe because is insert into the"FOR"
SO my question is : "How to move this Circle line if that's possible with the "FOR" ?
I hope I've Been clearer
Anyway, Thanks for all
I'll answer your second question first:
Runtime:addEventListener( "enterFrame", cube )
The function addEventListener adds a listener to the object’s list of listeners. When the named event occurs (in this case "enterFrame"), the listener will be invoked and be supplied with a table representing the event. In your code, the listener will call cube() on every frame (normaly, games run at 60 frames per second).
timer.performWithDelay(delay, listener [, iterations])
performWithDelay does what it says it does: Call a specified function after a delay. The timer function returns an object that can be used with other timer.* functions. In your code timer.performWithDelay(1, cube, -1) the function is calling cube() every 1ms and it is going to do so forever. This is not a good thing to do. There's nothing catching the return of the timer function and it is going to be running forever.
Now, to answer your main question. I believe what you are trying to do is create a square an move it in the screen. If that's correct, here's how you should do it:
local square = display.newRect(100,100,50,50)
local speed = 2
-- called every frame
local function moveSquare()
square.x = square.x + speed
end
Runtime:addEventListener("enterFrame", moveSquare)
The reason your code doesn't do what you want it to do is because you misunderstood a some basic CoronaSDK things.
Hope this little code helps you to understand more about how CoronaSDK works. Don't forget to check the documentation of Corona in http://docs.coronalabs.com/
You're creating an object locally in a loop and trying to move it outside of the loop. This doesn't work due to the way lua uses local variables. See http://www.lua.org/pil/4.2.html for more info about this.
Also, you'll need to place the objects into a single display group in order to move them easily. If you're using Box2D physics at all, I recommend reading up on it more at http://docs.coronalabs.com/api/library/physics/index.html.
Your code:
for i=1,10,1 do
local Circle = display.newCircle(50, 20, 20)
Circle.x = _x + (50*i)
Circle.y = _y
end
Should Be Changed to:
local Circle = display.newGroup(); --Forward declaration of Variable. Place this before any calls for it.
local speed = 2;
for i=1,10,1 do
local object = display.newCircle(50,20,20);
object.x = _x + (50*i);
object.y = _y;
Circle:insert(object); --Insert this local object into the display group
end
function moveCircle()
Circle.x = Circle.x + speed;
end
Runtime:addEventListener( "enterFrame", moveCircle);
This will move the Circle line every frame, on the X-axis, by the speed variable's value.
If you're trying to move it with a for-loop, then we'd need to see more of you code in context.

Snakes and Ladders AS3.. how can a movie clip climb a ladder?

I am having this problem in developing this snakes and ladders game and i am very much hoping that you guys can help me out. i already created the board and the avatar. only thing is i cant make the avatar move up the ladder, and move down with the snake. can somebody help me? i am very much desperate right now, and every help is appreciated, thank you guys!
EDIT:
here's the code that i have written so far here are some of the codes I have written so far..
stop();
var xCoord:Array = [141,251,360,471,580,691,799,910,1019,1127,1238,1238,1127,1019,910,799,691,580,471,360,251,251,360,471,580,691,799,910,1019,1127,1238,1238,1127,1019,910,799,691,580,471,360,251,251,360,471,580,691,799,910,1019,1127,1238,1238,1127,1019,910,799,691,580,471,360,251,251,360,471,580,691,799,910,1019,1127,1238,1238,1127,1019,910,799,691,580,471,360,251,251,360,471,580,691,799,910,1019,1127,1238,1238,1127,1019,910,799,691,580,471,360,251];
var yCoord:Array = [675,670,670,670,670,670,670,670,670,670,670,602,602,602,602,602,602,602,602,602,602,534,534,534,534,534,534,534,534,534,534,466,466,466,466,466,466,466,466,466,466,399,399,399,399,399,399,399,399,399,399,331,331,331,331,331,331,331,331,331,331,262,262,262,262,262,262,262,262,262,262,195,195,195,195,195,195,195,195,195,195,127,127,127,127,127,127,127,127,127,127,60,60,60,60,60,60,60,60,60,60];
var arrSquares:Array = new Array(xCoord.length);
var spaceIndex:Number = 0;
var delay:Number = 400;
var tm:Timer = new Timer(delay);
tm.addEventListener(TimerEvent.TIMER, mover);
tm.addEventListener(TimerEvent.TIMER_COMPLETE, moveDone);
spinner.addEventListener(MouseEvent.CLICK, doSpin);
var total:Number =0;
function doSpin(mevt:MouseEvent):void {
var rn:Number = Math.round(5*Math.random()+1);
txtCount.text = String(rn);
total = total + rn;
txtTotal.text = String(total);
txtCount.visible = true;
spinner.removeEventListener(MouseEvent.CLICK, doSpin);
tm.reset();
tm.repeatCount = rn;
tm.start();
}
function mover(tevt:TimerEvent):void {
spaceIndex = (spaceIndex+1)%(xCoord.length);
chip.x = xCoord[spaceIndex];
chip.y = yCoord[spaceIndex];
}
function moveDone(tevt:TimerEvent):void {
spinner.addEventListener(MouseEvent.CLICK, doSpin);
txtCount.visible = false;
}
i dont know where to put the if statement of executing the motion tween attached to the chip(avatar)
Well here are my initial thoughts. I would create an animation with your character who you want to move up and down. To make it simple, make an animation for climbing, then one for falling. It's really easy to do, just use the tween option on the timeline after inserting your keyframes.
Looks like you've created your animations. Now, whether or not he slides up or falls down depends on where your snakes and ladders are. Only you know that, so at those particular spots on your board (for example, x = 200 and y = 200) we want the if statement to occur. But we only want it to occur after your avatar is done moving. Probably create a new function and add the following to the mover function
var checkX:Number = chip.x;
var checkY:Number = chip.y
checkLandingSpace(checkX,checkY);
Now let's make a function checkLandingSpace which will check if we are on a shoot or ladder
function checkLandingSpace(checkX:Number,checkY:Number):void
{
if (checkX = (your point) || (another point) //first check all x points...continue like this for all points where a ladder is...the || means or
{
if (checkY = (your points....etc)
{
mc_avatarLadder.play(); //choose your instance name to be mc_avatar, then play the tween
}
}
}
Or check this post for equating one variable to any element in an array If [Get Variable] is equal to [Array]
Now write the that for your ladder. Then do the exact same thing with all of your shoots points. Except, make a new animation with instance name mc_avatarShoot then just say mc_avatarShoot.play();
After that, make sure on the last frame for both instances, you just put in gotoAndStop(1); just to make sure it's ready next time you go to play the animation.
Of course, adjust your timer appropriately. This should pretty much do it, there might be a couple things to adjust for your own game, but follow this and understand it and you'll get it.

Ideas for jumping in 2D with Actionscript 3 [included attempt]

So, I'm working on the basics of Actionscript 3; making games and such.
I designed a little space where everything is based on location of boundaries, using pixel-by-pixel movement, etc.
So far, my guy can push a box around, and stops when running into the border, or when try to the push the box when it's against the border.
So, next, I wanted to make it so when I bumped into the other box, it shot forward; a small jump sideways.
I attempted to use this (foolishly) at first:
// When right and left borders collide.
if( (box1.x + box1.width/2) == (box2.x - box2.width/2) ) {
// Nine times through
for (var a:int = 1; a < 10; a++) {
// Adds 1, 2, 3, 4, 5, 4, 3, 2, 1.
if (a <= 5) {
box2.x += a; }
else {
box2.x += a - (a - 5)*2 } } }
Though, using this in the function I had for the movement (constantly checking for keys up, etc) does this all at once.
Where should I start going about a frame-by-frame movement like that? Further more, it's not actually frames in the scene, just in the movement.
This is a massive pile of garbage, I apologize, but any help would be appreciated.
try doing something like: (note ev.target is the box that you assigned the listener to)
var boxJumpDistance:Number = 0;
function jumpBox(ev:Event){
if (boxJumpDistance<= 5) {
ev.target.x += boxJumpDistance; }
else if(boxJumpDistance<=10){
ev.target.x += boxJumpDistance - (boxJumpDistance - 5)*2
}
else{
boxJumpDistance = 0;
ev.target.removeEventListener(Event.ENTER_FRAME, jumpBox);
}
}
then instead of running the loop, just add a listener:
box2.addEventListener(Event.ENTER_FRAME, jumpBox);
although this at the moment only works for a single box at a time (as it is only using one tracking variable for the speed), what you would really want to do is have that function internally to the box class, but im unsure how your structure goes. the other option would be to make an array for the boxes movement perhaps? loop through the array every frame. boxesMoveArray[1] >=5 for box 1, etc.