Strange behaviour when changing velocity

Hi,

I’m seeing some strange behaviour when trying to change linear velocity after ball collision.

I’m using a zero gravity and a ball moving at contant speed. Speed is aplied using a linear impulse.

Here is my physics setup:

[lua]
physics:start()
physics.setReportCollisionsInContentCoordinates( true )
physics.setGravity(0, 0)
[/lua]

And my ball display object with dynamic body:

[lua]
local bo = display.newImageRect(“images/rubkuglica.png”, ball.size * 2, ball.size * 2)
func:scaleImage(bo)
bo.x = _W / 2
bo.y = _H / 2
stage:insert(bo)
    
local diameter = ball.size * 2
if (diameter > bo.width) then
    diameter = bo.width
end
if (diameter > bo.height) then
    diameter = bo.height
end

physics.addBody( bo, “dynamic”, { density=0, friction=0, bounce=1, radius=diameter/2 } )
    
bo:setFillColor( color[1], color[2], color[3] )
bo.colorIndex = colorIndex
bo.isBall = true
bo.collision = collisionFunction
bo.linearDamping = 0
bo.angularDamping = 0
bo.angularVelocity = 0
bo.gravityScale = 0
bo.isFixedRotation = true
bo:addEventListener( “collision”, bo )
[/lua]

Here is how I move the ball at constant speed:

[lua]
ball.object:applyLinearImpulse( ball.startX * ball.object.mass, ball.startY * ball.object.mass, ball.object.x, ball.object.y )
[/lua]

The strange thing is when I try to stop the ball by setting linear velocity to zero, it does not stop, it coninues to move with a slower speed.

[lua]
timer.performWithDelay(20, function()
        local vx, vy = collision.ball.object:getLinearVelocity()
        collision.ball.object:setLinearVelocity(0, 0)
        print(“Change velocity!!!”)
    end)
[/lua]

The even stranger thing happens when I set linear velocity to current velocity * -3. Then the velocity changes to the opposite value but the change of direction is very lagy and ugly.

[lua]
timer.performWithDelay(20, function()
        local vx, vy = collision.ball.object:getLinearVelocity()
        collision.ball.object:setLinearVelocity(vx * -3, vy * -3)
        print(“Change velocity!!!”)
    end)
[/lua]

Am I missing something or is Box2D that bad for zero gravity games? Tnx for help.

Daniel

Hi Daniel,

I don’t see the code for your “collisionFunction” function. Can you show that?

Thanks,

Brent

Sure. Its a very large function as I handle collision with many objects. Here are the important parts that include physics:

[lua]

if (other.isMultiplier) then

    if (changeSpeed == true) then

            --Here I increase speed using a linear impulse. This works fine

            local vx, vy = collision.ball.object:getLinearVelocity()
                local impulseX = (vx * collision.ball.increaseSpeedFactor / (collision.ball.multiplyScore / collision.ball.multiplyScalator)) * collision.ball.object.mass
            local impulseY = (vy * collision.ball.increaseSpeedFactor / (collision.ball.multiplyScore / collision.ball.multiplyScalator)) * collision.ball.object.mass
            if (isMinus == true) then
                    collision.ball.object:applyLinearImpulse( -impulseX, -impulseY, collision.ball.object.x, collision.ball.object.y )
                     collision.ball.multiplyScalator = collision.ball.multiplyScalator - 0.5 --0.4
            else
                     collision.ball.object:applyLinearImpulse( impulseX, impulseY, collision.ball.object.x, collision.ball.object.y )
                     collision.ball.multiplyScalator = collision.ball.multiplyScalator + 0.5 --0.4
            end
        end

elseif (other.isWall) then
                collision.ball.activePowerup = “wall”
                collision.ball:setSpriteSequence(“powerup”)

                --Here I want to change ball’s direction using setLinearVelocity

                --It sould be collision.ball.object:setLinearVelocity(vx * -1, vy * -1) but it’s not

                timer.performWithDelay(20, function()
                        local vx, vy = collision.ball.object:getLinearVelocity()
                        collision.ball.object:setLinearVelocity(vx * -3, vy * -3)
                        print(“Change velocity!!!”)
                    end)

end

[/lua]

Daniel

Hi Daniel,

Before I inspect the code in more detail, is your desire to move this object on a set linear velocity (which may vary) or to “push it around” via impulse forces? Remember that the former sets the velocity at a declared speed, while the latter is more complex to use because you’re applying varying degrees of force which must off-set the object’s velocity in the current direction, and so forth.

Brent

Brent,

thanks, but I do not use applyLinearImpulse and setLinearVelocity at the same time. Can’t I use both for changing my ball’s movement / speed?

Daniel

Hi Daniel,

Yes, you can use both, but remember that setting a linear velocity (setLinearVelocity()) directly sets those specific velocity values on the object. Applying a linear impulse (applyLinearImpulse()) or applying force (applyForce()) adds those amounts to whatever the object is currently doing. So, if you apply an impulse to an object which is already moving, you need to consider if the object is moving in opposition to that impulse, in which case, you’ll need to apply much greater impulse to force the object back in the other direction or whatever.

If you still want to use impulse values to send the object in a specific direction, you could set its linear velocity to 0,0, then afterwards (perhaps on a 10-20 millisecond timer) apply the new impulse value to it.

Does that clarify somewhat?

Brent

Thanks for the detailed explanation. I understand how forces / impulses work.

However, setLinearVelocity does not work as expected in my case.

Let me try to explain the problem more clearly using theese two timers:

[lua]

   timer.performWithDelay(1000, function()
        local vx, vy = ball.object:getLinearVelocity()
        print(“Velocity”, vx, vy)
      end, 0)

   timer.performWithDelay(10000, function()
        ball.object:setLinearVelocity(0, 0)
        print(“Velocity set to zero”)
      end, 0)

[/lua]

On start game a linear impulse is applied to get the ball moving.

After 10 seconds a velocity is set to zero.

The ball should stop, right? But, it doesn’t!

w8pcly.png

Daniel

Hi Daniel,

I see no “physical” reason why this isn’t working. Are you sure that it’s properly referencing the ball? Try print()-ing out the value of the object (its internal Lua reference) directly after you create it, then ensure that the value of “ball.object” is the exact same when you try to effect it in the timer functions.

Also, is there a reason why you’re calling these timers repeatedly? Did you mean to trigger them only once?

Brent

You are right. It was my mistake. The physics engine is working just as expected. Thanks for your suggestions, they were very helpfull.

I have forgotten that I have added a smaller sprite display / physics object ‘over’ my ball physics object. I joined the two using a pivot joint. The linear impulse was applied on both objects (the bigger and the smaller ball) so they were moving fine at a same, constant velocity. But when I have set the linear velocity only on one object, the other one pulled it and that is the reason why I got this ‘not at all strange’ velocity behaviour.

What I should have done is to set linear velocity on both joined objects, like this:

[lua]

timer.performWithDelay(10000, function()
    ball.object:setLinearVelocity(0, 0)
    ball.sprite:setLinearVelocity(0, 0)
    print(“Velocity set to zero”)
end, 0)

[/lua]

Btw. I am not using these timers, there purpose was just for demonstration. Thanks again for helping.

Solution:

  • If you are using a joint don’t forget about it (as I did :))
  • Then when you want to stop joined objects, set velocity to zero on all joined objects

Daniel

Hi Daniel,

I don’t see the code for your “collisionFunction” function. Can you show that?

Thanks,

Brent

Sure. Its a very large function as I handle collision with many objects. Here are the important parts that include physics:

[lua]

if (other.isMultiplier) then

    if (changeSpeed == true) then

            --Here I increase speed using a linear impulse. This works fine

            local vx, vy = collision.ball.object:getLinearVelocity()
                local impulseX = (vx * collision.ball.increaseSpeedFactor / (collision.ball.multiplyScore / collision.ball.multiplyScalator)) * collision.ball.object.mass
            local impulseY = (vy * collision.ball.increaseSpeedFactor / (collision.ball.multiplyScore / collision.ball.multiplyScalator)) * collision.ball.object.mass
            if (isMinus == true) then
                    collision.ball.object:applyLinearImpulse( -impulseX, -impulseY, collision.ball.object.x, collision.ball.object.y )
                     collision.ball.multiplyScalator = collision.ball.multiplyScalator - 0.5 --0.4
            else
                     collision.ball.object:applyLinearImpulse( impulseX, impulseY, collision.ball.object.x, collision.ball.object.y )
                     collision.ball.multiplyScalator = collision.ball.multiplyScalator + 0.5 --0.4
            end
        end

elseif (other.isWall) then
                collision.ball.activePowerup = “wall”
                collision.ball:setSpriteSequence(“powerup”)

                --Here I want to change ball’s direction using setLinearVelocity

                --It sould be collision.ball.object:setLinearVelocity(vx * -1, vy * -1) but it’s not

                timer.performWithDelay(20, function()
                        local vx, vy = collision.ball.object:getLinearVelocity()
                        collision.ball.object:setLinearVelocity(vx * -3, vy * -3)
                        print(“Change velocity!!!”)
                    end)

end

[/lua]

Daniel

Hi Daniel,

Before I inspect the code in more detail, is your desire to move this object on a set linear velocity (which may vary) or to “push it around” via impulse forces? Remember that the former sets the velocity at a declared speed, while the latter is more complex to use because you’re applying varying degrees of force which must off-set the object’s velocity in the current direction, and so forth.

Brent

Brent,

thanks, but I do not use applyLinearImpulse and setLinearVelocity at the same time. Can’t I use both for changing my ball’s movement / speed?

Daniel

Hi Daniel,

Yes, you can use both, but remember that setting a linear velocity (setLinearVelocity()) directly sets those specific velocity values on the object. Applying a linear impulse (applyLinearImpulse()) or applying force (applyForce()) adds those amounts to whatever the object is currently doing. So, if you apply an impulse to an object which is already moving, you need to consider if the object is moving in opposition to that impulse, in which case, you’ll need to apply much greater impulse to force the object back in the other direction or whatever.

If you still want to use impulse values to send the object in a specific direction, you could set its linear velocity to 0,0, then afterwards (perhaps on a 10-20 millisecond timer) apply the new impulse value to it.

Does that clarify somewhat?

Brent

Thanks for the detailed explanation. I understand how forces / impulses work.

However, setLinearVelocity does not work as expected in my case.

Let me try to explain the problem more clearly using theese two timers:

[lua]

   timer.performWithDelay(1000, function()
        local vx, vy = ball.object:getLinearVelocity()
        print(“Velocity”, vx, vy)
      end, 0)

   timer.performWithDelay(10000, function()
        ball.object:setLinearVelocity(0, 0)
        print(“Velocity set to zero”)
      end, 0)

[/lua]

On start game a linear impulse is applied to get the ball moving.

After 10 seconds a velocity is set to zero.

The ball should stop, right? But, it doesn’t!

w8pcly.png

Daniel

Hi Daniel,

I see no “physical” reason why this isn’t working. Are you sure that it’s properly referencing the ball? Try print()-ing out the value of the object (its internal Lua reference) directly after you create it, then ensure that the value of “ball.object” is the exact same when you try to effect it in the timer functions.

Also, is there a reason why you’re calling these timers repeatedly? Did you mean to trigger them only once?

Brent

You are right. It was my mistake. The physics engine is working just as expected. Thanks for your suggestions, they were very helpfull.

I have forgotten that I have added a smaller sprite display / physics object ‘over’ my ball physics object. I joined the two using a pivot joint. The linear impulse was applied on both objects (the bigger and the smaller ball) so they were moving fine at a same, constant velocity. But when I have set the linear velocity only on one object, the other one pulled it and that is the reason why I got this ‘not at all strange’ velocity behaviour.

What I should have done is to set linear velocity on both joined objects, like this:

[lua]

timer.performWithDelay(10000, function()
    ball.object:setLinearVelocity(0, 0)
    ball.sprite:setLinearVelocity(0, 0)
    print(“Velocity set to zero”)
end, 0)

[/lua]

Btw. I am not using these timers, there purpose was just for demonstration. Thanks again for helping.

Solution:

  • If you are using a joint don’t forget about it (as I did :))
  • Then when you want to stop joined objects, set velocity to zero on all joined objects

Daniel