How to stop and restart animation from where it was stopped

Hi,

In my game I want my character play different animation when it goes up and down, and stop all animation when it stay still.

I’m using following code for animation of player:-

in init() method:->
sprite_Player = cocos2d::Sprite::create();
Vector<SpriteFrame*> animFramesPlayer;
animFramesPlayer.reserve(4);
animFramesPlayer.pushBack(SpriteFrame::create(“playerUp/0.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerUp/1.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerUp/2.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerUp/3.png”, Rect(0, 0, 85, 101)));
Animation* animationPlayer = Animation::createWithSpriteFrames(animFramesPlayer, 0.15f);
Animate* animatePlayer = Animate::create(animationPlayer);

//// run it and repeat it forever
sprite_Player->runAction(RepeatForever::create(animatePlayer));
this->addChild(sprite_Player);
playerX = origin.x + visibleSize.width / 2;
playerY = origin.y + visibleSize.height / 2;
sprite_Player->setPosition(Vec2(playerX, playerY));





sprite_Up = Sprite::create("arrow_up.png");//nilesh
this->addChild(sprite_Up, 3);
sprite_Up->setPosition(Vec2(GameScene::origin.x + GameScene::sprite_Up->getContentSize().width / 2,
	GameScene::origin.y + visibleSize.height / 2));



//////////////Listener for UP////////////////////////
auto listenersprite_Up = EventListenerTouchOneByOne::create();

// trigger when you push down
listenersprite_Up->onTouchBegan = [&](Touch* touch, Event* event){

	auto sprite_Up = event->getCurrentTarget();
	Point pt = touch->getLocation();
	Rect recTemp = sprite_Up->boundingBox();
	if (recTemp.containsPoint(pt) ) {
		
		isTouchDown = false;
		isTouchUp = true;
		isTouchRight = false;
		isTouchLeft = false;
		l->setString("UUUp touched");
		
	}

	return true; // if you are consuming it
};

// trigger when moving touch
listenersprite_Up->onTouchMoved = [](Touch* touch, Event* event){
	///GameScene::isTouchDown = false;
};

// trigger when you let up
listenersprite_Up->onTouchEnded = [&](Touch* touch, Event* event){
	
	isTouchDown = false;
	isTouchUp = false;
	isTouchRight = false;
	isTouchLeft = false;
	l->setString("UUUp ENDED");
};

// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listenersprite_Up, sprite_Up);

//////////////Listener for UP End////////////////////////

sprite_Down = Sprite::create(“arrow_down.png”);//nilesh
this->addChild(sprite_Down, 3);
sprite_Down->setPosition(Vec2(GameScene::origin.x+ visibleSize.width - GameScene::sprite_Down->getContentSize().width,
GameScene::origin.y + visibleSize.height / 2));
//sprite_Up->setColor(Color3B(255, 0, 0));

//////////////Listener for Down////////////////////////
auto listenersprite_Down = EventListenerTouchOneByOne::create();

// trigger when you push down
listenersprite_Down->onTouchBegan = [&](Touch* touch, Event* event){

	auto sprite_Down = event->getCurrentTarget();
	Point pt = touch->getLocation();
	Rect recTemp = sprite_Down->boundingBox();
	if (recTemp.containsPoint(pt)) {

		isTouchDown = true;
		isTouchUp = false;
		isTouchRight = false;
		isTouchLeft = false;
		l->setString("UUUp touched Down");

	}

	return true; // if you are consuming it
};

// trigger when moving touch
listenersprite_Down->onTouchMoved = [](Touch* touch, Event* event){
	///GameScene::isTouchDown = false;
};

// trigger when you let up
listenersprite_Down->onTouchEnded = [&](Touch* touch, Event* event){

	isTouchDown = false;
	isTouchUp = false;
	isTouchRight = false;
	isTouchLeft = false;
	l->setString("UUUp Down ENDED");
};

// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listenersprite_Down, sprite_Down);

//////////////Listener for Down End////////////////////////

And the update() method is as follows:-

void GameScene::update(float delta)
{
if (isTouchUp)
{
playerY = playerY + 0.6f;
sprite_Player->setPosition(Vec2(playerX, playerY));
}

if (isTouchDown)
{
	playerY = playerY - 0.6f;
	sprite_Player->setPosition(Vec2(playerX, playerY));
}

}

Now how to start animation when user presses up or down button.

And how to stop animation when user comes in onTouchEnded method;

You could prevent the animation from resetting to original frame, retain the RepeatForever action and stop/run it on the object when necessary.

animationPlayer->setRestoreOriginalFrame(false)
auto action = RepeatForever::create(animatePlayer);
action->retain(); //release when you cleanup

start animation

sprite_Player->runAction(action);

stop animation

sprite_Player->stopAction(action);

Hi almax27,

Thanks for your reply.

I have changed the code as you said.

But the game crashes. And the output window shows that “The program ‘[3428] TaskHost.exe’ has exited with code -1073741819 (0xc0000005) ‘Access violation’.”

My code is as follows:

In init method I code for player animation as follows:-

sprite_Player = cocos2d::Sprite::create();
Vector<SpriteFrame*> animFramesPlayer;
animFramesPlayer.reserve(4);
animFramesPlayer.pushBack(SpriteFrame::create(“playerLeft/0.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerLeft/1.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerLeft/2.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerLeft/3.png”, Rect(0, 0, 85, 101)));

Animation* animationPlayer = Animation::createWithSpriteFrames(animFramesPlayer, 0.3f);
Animate* animatePlayer = Animate::create(animationPlayer);
    animationPlayer->setRestoreOriginalFrame(false);

animatePlayer->retain();

sprite_Player->runAction(RepeatForever::create(animatePlayer));
this->addChild(sprite_Player);
playerX = origin.x + visibleSize.width / 2;
playerY = origin.y + visibleSize.height / 2;
sprite_Player->setPosition(Vec2(playerX, playerY));

And on button listener I code as follows:-

sprite_Left = Sprite::create(“arrow_left.png”);//nilesh
this->addChild(sprite_Left, 3);
sprite_Left->setPosition(Vec2(GameScene::origin.x + visibleSize.width - GameScene::sprite_Left->getContentSize().width,
GameScene::origin.y-10 - sprite_Left->getContentSize().height + visibleSize.height / 2));

//////////////Listener for Left////////////////////////
auto listenersprite_left = EventListenerTouchOneByOne::create();

// trigger when you push down
listenersprite_left->onTouchBegan = [&](Touch* touch, Event* event){
	sprite_Player->runAction(animatePlayer);
	auto sprite_Left = event->getCurrentTarget();
	Point pt = touch->getLocation();
	Rect recTemp = sprite_Left->boundingBox();
	if (recTemp.containsPoint(pt)) {

		isTouchDown = false;
		isTouchUp = false;
		isTouchRight = false;
		isTouchLeft = true;
		l->setString("UUUp touched Down");

	}

	return true; // if you are consuming it
};

// trigger when moving touch
listenersprite_left->onTouchMoved = [](Touch* touch, Event* event){
	///GameScene::isTouchDown = false;
};

// trigger when you let up
listenersprite_left->onTouchEnded = [&](Touch* touch, Event* event){
	sprite_Player->stopAction(animatePlayer);
	isTouchDown = false;
	isTouchUp = false;
	isTouchRight = false;
	isTouchLeft = false;
	l->setString("UUUp Down ENDED");
};

// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listenersprite_left, sprite_Left);

//////////////Listener for Left End////////////////////////

When I run the project the player animation is running properly.

But when I presses the button for moving the player then the game crashes.

Please correct me If I misunderstood you.

Thanks

You can’t run an action that is already running, so you shouldn’t have the first runAction() outside the listener. However I’m not sure this approach will work because when Animate is added, startWithTarget() is called which resets the frame to 0. Perhaps you should try calling pause() and resume() on your sprite instead. This will pause any scheduled functions, actions and event listeners on the sprite too however.

Hi almax27,

I changed my code as follow I don’t know whether it is the right way of doing it or not.

But it is producing the desired behavior.

Please tell me if there is a better way for moving a animated player left, right, up, and down.

In init() method I created the player sprite as follows:-

sprite_Player = cocos2d::Sprite::create(“playerUp/1.png”);
this->addChild(sprite_Player);
playerX = origin.x + visibleSize.width / 2;
playerY = origin.y + visibleSize.height / 2;
sprite_Player->setPosition(Vec2(playerX, playerY));

After that I created 4 method for player’s left ,right,up and down animation which are as follows:-

void GameScene::playerDownAni(){
Vector<SpriteFrame*> animFramesPlayer;
animFramesPlayer.reserve(4);
animFramesPlayer.pushBack(SpriteFrame::create(“playerDown/0.png”, Rect(0, 0, 37, 82)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerDown/1.png”, Rect(0, 0, 37, 82)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerDown/2.png”, Rect(0, 0, 37, 82)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerDown/3.png”, Rect(0, 0, 37, 82)));
Animation* animationPlayer = Animation::createWithSpriteFrames(animFramesPlayer, 0.2f);
Animate* animatePlayer = Animate::create(animationPlayer);

sprite_Player->runAction(RepeatForever::create(animatePlayer));

}

void GameScene::playerUpAni(){
Vector<SpriteFrame*> animFramesPlayer;
animFramesPlayer.reserve(4);
animFramesPlayer.pushBack(SpriteFrame::create(“playerUp/2.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerUp/3.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerUp/4.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerUp/5.png”, Rect(0, 0, 85, 101)));
Animation* animationPlayer = Animation::createWithSpriteFrames(animFramesPlayer, 0.2f);
Animate* animatePlayer = Animate::create(animationPlayer);

sprite_Player->runAction(RepeatForever::create(animatePlayer));

}

void GameScene::playerLeftAni(){

l->setString("AAAAAAAAAAAAAAAAA");
Vector<SpriteFrame*> animFramesPlayer1;
animFramesPlayer1.reserve(4);
animFramesPlayer1.pushBack(SpriteFrame::create("playerLeft/0.png", Rect(0, 0, 85, 101)));
animFramesPlayer1.pushBack(SpriteFrame::create("playerLeft/1.png", Rect(0, 0, 85, 101)));
animFramesPlayer1.pushBack(SpriteFrame::create("playerLeft/2.png", Rect(0, 0, 85, 101)));
animFramesPlayer1.pushBack(SpriteFrame::create("playerLeft/3.png", Rect(0, 0, 85, 101)));
Animation* animationPlayer1 = Animation::createWithSpriteFrames(animFramesPlayer1, 0.2f);
Animate* animatePlayer1 = Animate::create(animationPlayer1);

sprite_Player->runAction(RepeatForever::create(animatePlayer1));

}

void GameScene::playerRightAni(){
Vector<SpriteFrame*> animFramesPlayer;
animFramesPlayer.reserve(4);
animFramesPlayer.pushBack(SpriteFrame::create(“playerRight/0.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerRight/1.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerRight/2.png”, Rect(0, 0, 85, 101)));
animFramesPlayer.pushBack(SpriteFrame::create(“playerRight/3.png”, Rect(0, 0, 85, 101)));
Animation* animationPlayer = Animation::createWithSpriteFrames(animFramesPlayer, 0.2f);
Animate* animatePlayer = Animate::create(animationPlayer);

animatePlayer->retain();	
sprite_Player->runAction(RepeatForever::create(animatePlayer));

}

After that I called the above method from each button’s touched event as follows:-

sprite_Up = Sprite::create("arrow_up.png");//nilesh
this->addChild(sprite_Up, 3);
sprite_Up->setPosition(Vec2(GameScene::origin.x + GameScene::sprite_Up->getContentSize().width / 2,
	GameScene::origin.y + visibleSize.height / 2));
//sprite_Up->setColor(Color3B(255, 0, 0));


//////////////Listener for UP////////////////////////
auto listenersprite_Up = EventListenerTouchOneByOne::create();

// trigger when you push down
listenersprite_Up->onTouchBegan = [&](Touch* touch, Event* event){
	
	auto sprite_Up = event->getCurrentTarget();
	Point pt = touch->getLocation();
	Rect recTemp = sprite_Up->boundingBox();
	if (recTemp.containsPoint(pt) ) {
		GameScene::playerUpAni();
		isTouchDown = false;
		isTouchUp = true;
		isTouchRight = false;
		isTouchLeft = false;
		l->setString("UUUp touched");
		
	}

	return true; // if you are consuming it
};

// trigger when moving touch
listenersprite_Up->onTouchMoved = [](Touch* touch, Event* event){
	///GameScene::isTouchDown = false;
};

// trigger when you let up
listenersprite_Up->onTouchEnded = [&](Touch* touch, Event* event){
	sprite_Player->stopAllActions();
	sprite_Player->setSpriteFrame(SpriteFrame::create("playerUp/1.png", Rect(0, 0, 85, 101)));
	isTouchDown = false;
	isTouchUp = false;
	isTouchRight = false;
	isTouchLeft = false;
	l->setString("UUUp ENDED");
};

// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listenersprite_Up, sprite_Up);

//////////////Listener for UP End////////////////////////



sprite_Down = Sprite::create("arrow_down.png");//nilesh
this->addChild(sprite_Down, 3);
sprite_Down->setPosition(Vec2(GameScene::origin.x+ visibleSize.width - GameScene::sprite_Down->getContentSize().width,
	GameScene::origin.y + visibleSize.height / 2));
//sprite_Up->setColor(Color3B(255, 0, 0));


//////////////Listener for Down////////////////////////
auto listenersprite_Down = EventListenerTouchOneByOne::create();

// trigger when you push down
listenersprite_Down->onTouchBegan = [&](Touch* touch, Event* event){

	auto sprite_Down = event->getCurrentTarget();
	Point pt = touch->getLocation();
	Rect recTemp = sprite_Down->boundingBox();
	if (recTemp.containsPoint(pt)) {
		GameScene::playerDownAni();
		isTouchDown = true;
		isTouchUp = false;
		isTouchRight = false;
		isTouchLeft = false;
		l->setString("UUUp touched Down");

	}

	return true; // if you are consuming it
};

// trigger when moving touch
listenersprite_Down->onTouchMoved = [](Touch* touch, Event* event){
	///GameScene::isTouchDown = false;
};

// trigger when you let up
listenersprite_Down->onTouchEnded = [&](Touch* touch, Event* event){
	sprite_Player->setSpriteFrame(SpriteFrame::create("playerDown/0.png", Rect(0, 0, 85, 101)));
	isTouchDown = false;
	isTouchUp = false;
	isTouchRight = false;
	isTouchLeft = false;
	l->setString("UUUp Down ENDED");
};

// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listenersprite_Down, sprite_Down);

//////////////Listener for Down End////////////////////////



sprite_Right = Sprite::create("arrow_right.png");//nilesh
this->addChild(sprite_Right, 3);
sprite_Right->setPosition(Vec2(GameScene::origin.x + visibleSize.width - GameScene::sprite_Right->getContentSize().width / 2,
	GameScene::origin.y - 2 * sprite_Right->getContentSize().height + visibleSize.height / 2));
//sprite_Up->setColor(Color3B(255, 0, 0));


//////////////Listener for Left////////////////////////
auto listenersprite_right = EventListenerTouchOneByOne::create();

// trigger when you push down
listenersprite_right->onTouchBegan = [&](Touch* touch, Event* event){
	//sprite_Player->runAction(animatePlayer);
	auto sprite_Right = event->getCurrentTarget();
	Point pt = touch->getLocation();
	Rect recTemp = sprite_Right->boundingBox();
	if (recTemp.containsPoint(pt)) {
		GameScene::playerRightAni();
		isTouchDown = false;
		isTouchUp = false;
		isTouchRight = true;
		isTouchLeft = false;
		l->setString("UUUp touched Down");

	}

	return true; // if you are consuming it
};

// trigger when moving touch
listenersprite_right->onTouchMoved = [](Touch* touch, Event* event){
	///GameScene::isTouchDown = false;
};

// trigger when you let up
listenersprite_right->onTouchEnded = [&](Touch* touch, Event* event){
	//sprite_Player->stopAllActions();// Action(animatePlayer);
	sprite_Player->setSpriteFrame(SpriteFrame::create("playerRight/0.png", Rect(0, 0, 85, 101)));
	isTouchDown = false;
	isTouchUp = false;
	isTouchRight = false;
	isTouchLeft = false;
	l->setString("UUUp Down ENDED");
};

// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listenersprite_right, sprite_Right);

//////////////Listener for Left End////////////////////////





sprite_Left = Sprite::create("arrow_left.png");//nilesh
this->addChild(sprite_Left, 3);
sprite_Left->setPosition(Vec2(GameScene::origin.x + GameScene::sprite_Left->getContentSize().width / 2,
	GameScene::origin.y - 2 * sprite_Left->getContentSize().height + visibleSize.height / 2));
//sprite_Up->setColor(Color3B(255, 0, 0));


//////////////Listener for Left////////////////////////
auto listenersprite_left = EventListenerTouchOneByOne::create();

// trigger when you push down
listenersprite_left->onTouchBegan = [&](Touch* touch, Event* event){
	
	//sprite_Player->runAction(animatePlayer);
	auto sprite_Left = event->getCurrentTarget();
	Point pt = touch->getLocation();
	Rect recTemp = sprite_Left->boundingBox();
	if (recTemp.containsPoint(pt)) {
		GameScene::playerLeftAni();
		isTouchDown = false;
		isTouchUp = false;
		isTouchRight = false;
		isTouchLeft = true;
		l->setString("UUUp LEFTTTTTTTTTTTT Down");

	}

	return true; // if you are consuming it
};

// trigger when moving touch
listenersprite_left->onTouchMoved = [](Touch* touch, Event* event){
	///GameScene::isTouchDown = false;
};

// trigger when you let up
listenersprite_left->onTouchEnded = [&](Touch* touch, Event* event){
	sprite_Player->stopAction(animatePlayer);
	sprite_Player->setSpriteFrame(SpriteFrame::create("playerLeft/0.png", Rect(0, 0, 85, 101)));
	isTouchDown = false;
	isTouchUp = false;
	isTouchRight = false;
	isTouchLeft = false;
	l->setString("UUUp Down ENDED");
};

// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listenersprite_left, sprite_Left);

//////////////Listener for Left End////////////////////////

Thanks.

1 Like