Sometimes, a specific 'player:setSequence' line doesn't work

Hello everyone from Corona community, I’m making my first app in Corona and I’m stuck in one little bug that I can’t fix or debug alone. 

As this is my first post in the forums and as I am a newbie in this environment, I choose this board to post, but if there is one that better suit my post, please let me know.

Well, my problem is the following:

I started making and Endless Runner app to learn the Corona SDK. Everything went fine and is working, but SOMETIMES the code to check if the player landed on the platform, and change his animation from “falling” to “running” doesn’t work, and he gets stuck on the “falling” animation while landed on the platform.

Normally, we would have this:

EdwrbRi.jpg

But sometimes, and I don’t know why, we have this:

wxx1fy3.jpg

I added some “prints” to the code, to make sure that the code that calls the “Player:setSequence” is being called, it is the case of the two “lets go” debug lines. They are printe before and after the setSequence command. Here are some code snippets:

function animatePlayer() --controla as animações de ação do jogador vx, vy = player:getLinearVelocity( ) local checkAgain --se o jogador está subindo no plano y, animação de pulo if vy \< 0 then player.gravityScale = 1 player:setSequence("jump1") checkAgain = true --se o jogador está descendo, animação de cair elseif vy \> 0 then if ( tapSwitch ) then --verifica se ele esta caindo ou planando player:setSequence("jump3") player.gravityScale = 0.05 else print("hey") player:setSequence("jump2") player.gravityScale = 1 end checkAgain = true --se jogador está parado no plano y, animação de corrida else if(checkAgain) then player:setSequence( "run" ) player:play() checkAgain = false end end end

This is the animation code, special atention to the “print(hey)”, that is the code to control when the player is “falling”

function onLocalCollision( event ) --controla toda as colisões do jogo (Jogador com o chão e jogador com os inimigos) local locPlayer local other if (event.phase == "began") then --o corona nao tem como saber qual object é qual numa colisão, aqui defino qual é qual através do nome do objeto if (event.object1.name=="player") then locPlayer = event.object1 other = event.object2 elseif (event.object2.name=="player") then locPlayer = event.object2 other = event.object1 else return end --colisão com o chão if (other.name=="p") then print("ho") audio.play( sfx.se2, { channel=2 } ) combo = 0 updateCombo() player.estado = 0 player:setLinearVelocity(0,0) player.gravityScale = 1 print("lets go") player:setSequence( "run" ) print("lets go") player:play()

Nos this is my collision function, the platform is called “p”. When is collides with the player, it prints “ho”, do some things, and I surrounded the setSequence with the prints “lets go”. And as you can see from the screenshots, they are all called, and it don’t print “hey” after, indicating that the code that make the player “fall” doesn’t get called again after the collision, so the case is that the setSequence(Run) is not working.

I don’t have a clue from where do I go from here. With these informations can somebody help me, or do you need some more code snippets to try a guess?

Thank you for you time!

Paulo, (a not english speaker)

Hi @Paulo,

This may be something related to your “animatePlayer” function, where it imagines that the player is jumping (but he’s not). Do you call this function some time after the player lands on the platform?

Brent

The “animatePlayer” function is called in the GameLoop function, that is called at every frame using the “timer.performWithDelay” function.

The only place that I call the setSequence for the falling animation is surrounded by the “hey” print:

print("hey") player:setSequence("jump2")

And when I land on the floor, this “print(hey)” doesn’t execute, but the falling animation plays otherwise.

The thing is, I am certain that the code for the landing works, because everytime i get these two prints on the log:

print("lets go") player:setSequence( "run" ) print("lets go")

But one time in 10, it’s like that “run” command is replaced by “jump2”. Because the player plays that animation, but the “hey” print above isn’t printed.

So… I have no idea.

Hi @Paulo,

Does your player (or the platforms) have any “bounce” value? Can you show me the “physics.addBody()” command which you’re using for the player and  the similar command for a platform? I think I might know why your sequence issue is happening, and this information might help me…

Thanks,

Brent

Sure thing!

They are in the scene:show( event ), “will” phase:

 --configura o jogador player = display.newSprite( mainGroup, sheet.player, sheetSequences.player ) player:setSequence( "run" ) player:play() player.name = "player" player.x = 60 player.y = 200 player.estado = 2 player.anchorX = 0.5 player.anchorY = 0.5 physics.addBody( player, "dynamic", { density=3, bounce=0, shape={-5, 49, -5, -25, 15, -25, 15, 49 } } ) player.isFixedRotation = true player.collision = onLocalCollision player:addEventListener( "collision" ) --configura o chão plataforma = display.newRect(0,300,12000,40) mainGroup:insert( plataforma ) plataforma:setFillColor( 0.0,0.0,0.0,0.0 ) plataforma.name = "p" physics.addBody( plataforma, "static", { bounce=0 } ) 

And these are the physic bodies of all the possible enemies:

 for i = #fase.enemiesTable, 1, -1 do local enemy if fase.enemiesTable[i].tipo == 1 then enemy = display.newSprite( mainGroup, sheet.enemy1, sheetSequences.enemy1 ) physics.addBody( enemy, "dynamic", { density=0.5, bounce=0, shape={-14, 14, -14, -10, 14, -10, 14, 14 } } ) elseif fase.enemiesTable[i].tipo == 2 then enemy = display.newSprite( mainGroup, sheet.enemy2, sheetSequences.enemy2 ) physics.addBody( enemy, "static", { density=0.3, bounce=0, shape={-14, 14, -14, -10, 14, -10, 14, 14 } } ) elseif fase.enemiesTable[i].tipo == 3 then enemy = display.newSprite( mainGroup, sheet.enemy1, sheetSequences.enemy1 ) physics.addBody( enemy, "dynamic", { density=0.5, bounce=1, shape={-14, 14, -14, -10, 14, -10, 14, 14 } } ) elseif fase.enemiesTable[i].tipo == 4 then enemy = display.newSprite( mainGroup, sheet.enemy3, sheetSequences.enemy3 ) physics.addBody( enemy, "dynamic", { density=0.3, bounce=0, shape={-14, 14, -14, -7, 14, -7, 14, 14 } } ) end enemy:play()

Hi Paulo,

Your physics setup looks fine. I think here is the cause:

When a collision occurs, even if there is no “bounce” there may be some very small “shaking” of the dynamic body, in a short amount of time when it “settles”. In most cases, you won’t even see it… it’s like tiny fractional values in velocity that only the physics engine might care about, for example the body might have a Y velocity of “-0.0000034” for just a moment, and then it might change to something else. This is the typical and expected behavior of the Box2D physics engine, not something that Corona really controls.

So, in your code, if you check (on a timer) that the upward velocity (vy) is <0, there may be some times when the player is “moving upward” by Box2D’s internal math, but to you, it appears the player is on the platform. This causes the game to occasionally change the animation sequence in ways you don’t expect.

A new question, before we proceed:

Is your goal with changing animation sequences specifically to indicate “Is the player standing on a platform or not?”. I don’t speak Portuguese, but I believe “se o jogador está subindo no plano y, animação de pulo” is approximately “if the player is not standing on the platform, animate the jump”? :slight_smile:

Brent

I’ll try to write the function in pseudocode and anotation in english to help you understand the function;

function animatePlayer() --control the animations of the player vx, vy = player:getLinearVelocity( ) --if the player is ascending in the Y-plane, play jump animation if vy \< 0 then player:setSequence("jump1") --if the player is descending in the Y-plane, plays one of the two falling animations elseif vy \> 0 then if ( tapSwitch ) then --if the player holds any button, the player floats player:setSequence("jump3") player.gravityScale = 0.05 else print("hey") player:setSequence("jump2") --if not, the player just falls player.gravityScale = 1 end --if the player is on the platform, plays the running animation else player:setSequence( "run" ) end end

I hide some stuff that i did to prevent the animation to stuck at the first frame, as this function is called every frame. It’s the checkAgain boolean, if it’s false it don’t repeat the setSequence all the time.

And your explanation of the little variations in velocity really makes sense, but I think that if it was the case, it should print the “hey” debug message anyway, and it don’t.

Anyway, in mid development I really tought that for the simplicity of my project, I shoul implement my own physics to make a more tight gameplay, but then i would have the rewrite the entire game for just one small bug.

HEY! I think I fixed it, even though I didn’t understand the problem.

In the funtion I declared the checkAgain as local, so it started as neither true or false. For most cases it worked, but somehow it messed the functionality sometimes. I declared it as a “global” (not a true global, just a local outside the scope of the function) and then I couldn’t reproduce the bug anymore, so I think it’s done.

Thank you VERY MUCH for your time, although I reached the solution “alone”, discussing the problem is always productive for us programmers haha, and anyway your insight about the box2D was very important, so thanks!

Great! :slight_smile:

You might also want to try adjusting your “vy” checks, just slightly away from 0, to prevent what (I think) is happening. So, perhaps like this:

if vy < -0.05 then

and…

elseif vy > 0.05 then

If you run your game timer frequently enough, the animation sequences should still update very soon after the player changes from moving upwards (jump) to moving downwards (falling).

Brent

Will do, thanks!

Hi @Paulo,

This may be something related to your “animatePlayer” function, where it imagines that the player is jumping (but he’s not). Do you call this function some time after the player lands on the platform?

Brent

The “animatePlayer” function is called in the GameLoop function, that is called at every frame using the “timer.performWithDelay” function.

The only place that I call the setSequence for the falling animation is surrounded by the “hey” print:

print("hey") player:setSequence("jump2")

And when I land on the floor, this “print(hey)” doesn’t execute, but the falling animation plays otherwise.

The thing is, I am certain that the code for the landing works, because everytime i get these two prints on the log:

print("lets go") player:setSequence( "run" ) print("lets go")

But one time in 10, it’s like that “run” command is replaced by “jump2”. Because the player plays that animation, but the “hey” print above isn’t printed.

So… I have no idea.

Hi @Paulo,

Does your player (or the platforms) have any “bounce” value? Can you show me the “physics.addBody()” command which you’re using for the player and  the similar command for a platform? I think I might know why your sequence issue is happening, and this information might help me…

Thanks,

Brent

Sure thing!

They are in the scene:show( event ), “will” phase:

 --configura o jogador player = display.newSprite( mainGroup, sheet.player, sheetSequences.player ) player:setSequence( "run" ) player:play() player.name = "player" player.x = 60 player.y = 200 player.estado = 2 player.anchorX = 0.5 player.anchorY = 0.5 physics.addBody( player, "dynamic", { density=3, bounce=0, shape={-5, 49, -5, -25, 15, -25, 15, 49 } } ) player.isFixedRotation = true player.collision = onLocalCollision player:addEventListener( "collision" ) --configura o chão plataforma = display.newRect(0,300,12000,40) mainGroup:insert( plataforma ) plataforma:setFillColor( 0.0,0.0,0.0,0.0 ) plataforma.name = "p" physics.addBody( plataforma, "static", { bounce=0 } ) 

And these are the physic bodies of all the possible enemies:

 for i = #fase.enemiesTable, 1, -1 do local enemy if fase.enemiesTable[i].tipo == 1 then enemy = display.newSprite( mainGroup, sheet.enemy1, sheetSequences.enemy1 ) physics.addBody( enemy, "dynamic", { density=0.5, bounce=0, shape={-14, 14, -14, -10, 14, -10, 14, 14 } } ) elseif fase.enemiesTable[i].tipo == 2 then enemy = display.newSprite( mainGroup, sheet.enemy2, sheetSequences.enemy2 ) physics.addBody( enemy, "static", { density=0.3, bounce=0, shape={-14, 14, -14, -10, 14, -10, 14, 14 } } ) elseif fase.enemiesTable[i].tipo == 3 then enemy = display.newSprite( mainGroup, sheet.enemy1, sheetSequences.enemy1 ) physics.addBody( enemy, "dynamic", { density=0.5, bounce=1, shape={-14, 14, -14, -10, 14, -10, 14, 14 } } ) elseif fase.enemiesTable[i].tipo == 4 then enemy = display.newSprite( mainGroup, sheet.enemy3, sheetSequences.enemy3 ) physics.addBody( enemy, "dynamic", { density=0.3, bounce=0, shape={-14, 14, -14, -7, 14, -7, 14, 14 } } ) end enemy:play()

Hi Paulo,

Your physics setup looks fine. I think here is the cause:

When a collision occurs, even if there is no “bounce” there may be some very small “shaking” of the dynamic body, in a short amount of time when it “settles”. In most cases, you won’t even see it… it’s like tiny fractional values in velocity that only the physics engine might care about, for example the body might have a Y velocity of “-0.0000034” for just a moment, and then it might change to something else. This is the typical and expected behavior of the Box2D physics engine, not something that Corona really controls.

So, in your code, if you check (on a timer) that the upward velocity (vy) is <0, there may be some times when the player is “moving upward” by Box2D’s internal math, but to you, it appears the player is on the platform. This causes the game to occasionally change the animation sequence in ways you don’t expect.

A new question, before we proceed:

Is your goal with changing animation sequences specifically to indicate “Is the player standing on a platform or not?”. I don’t speak Portuguese, but I believe “se o jogador está subindo no plano y, animação de pulo” is approximately “if the player is not standing on the platform, animate the jump”? :slight_smile:

Brent

I’ll try to write the function in pseudocode and anotation in english to help you understand the function;

function animatePlayer() --control the animations of the player vx, vy = player:getLinearVelocity( ) --if the player is ascending in the Y-plane, play jump animation if vy \< 0 then player:setSequence("jump1") --if the player is descending in the Y-plane, plays one of the two falling animations elseif vy \> 0 then if ( tapSwitch ) then --if the player holds any button, the player floats player:setSequence("jump3") player.gravityScale = 0.05 else print("hey") player:setSequence("jump2") --if not, the player just falls player.gravityScale = 1 end --if the player is on the platform, plays the running animation else player:setSequence( "run" ) end end

I hide some stuff that i did to prevent the animation to stuck at the first frame, as this function is called every frame. It’s the checkAgain boolean, if it’s false it don’t repeat the setSequence all the time.

And your explanation of the little variations in velocity really makes sense, but I think that if it was the case, it should print the “hey” debug message anyway, and it don’t.

Anyway, in mid development I really tought that for the simplicity of my project, I shoul implement my own physics to make a more tight gameplay, but then i would have the rewrite the entire game for just one small bug.

HEY! I think I fixed it, even though I didn’t understand the problem.

In the funtion I declared the checkAgain as local, so it started as neither true or false. For most cases it worked, but somehow it messed the functionality sometimes. I declared it as a “global” (not a true global, just a local outside the scope of the function) and then I couldn’t reproduce the bug anymore, so I think it’s done.

Thank you VERY MUCH for your time, although I reached the solution “alone”, discussing the problem is always productive for us programmers haha, and anyway your insight about the box2D was very important, so thanks!

Great! :slight_smile:

You might also want to try adjusting your “vy” checks, just slightly away from 0, to prevent what (I think) is happening. So, perhaps like this:

if vy < -0.05 then

and…

elseif vy > 0.05 then

If you run your game timer frequently enough, the animation sequences should still update very soon after the player changes from moving upwards (jump) to moving downwards (falling).

Brent

Will do, thanks!