How do i bounce an object at a constant speed?

Ok so go check out the attachment i added – Here what i need… So i have a box in the middle and when the game starts it starts moving in a random direction and when it hits something it bounces and keeps the same speed… 

Ok let say i have 4 objects and they all move out and start bouncing on each other… Over time they stop… I need them to bounce so if box 1 hits box 2 it bounce it and doesn’t slow down and doesn’t speed up…

How do i go about doing this? 

Thanks!

You’l have to reset the velocities after collisions.

Basic code is :

local math2d = require "plugin.math2d" local fixedRate = 100 -- 100 pixels per second function obj.postCollision( self )    local vx,vy = self:getLinearVelocity()    vx,vy = math2d.normalize( vx, vy )    vx,vy = math2d.scale( vx, vy, fixedRate )    self:setLinearVelocity( vx, vy ) end obj:listen("postCollision")

Use the math2d library to do the normalizing and scaling work: https://store.coronalabs.com/plugin/math2d

Wow, I just noticed my docs do not show how to use the scale function. 

This is how:

local vx,vy = 1, 1.5 vx,vy = math2d.scale( vx, vy, 2 ) print(vx,vy) -- prints 2 3

This works but it doesn’t bounce normally… when it collides it goes up and down and side to side but it doesn’t move slanted…

Check out the attachment below.

Thanks for the help!

  1. Did you get and set the x,y components of the vector correctly.  Better double check you didn’t swap and x for a y or vice versa.

  2. Consider adding a slight delay.

    local math2d = require “plugin.math2d” local fixedRate = 100 – 100 pixels per second function obj.postCollision( self ) timer.performWithDelay( 100, function() local vx,vy = self:getLinearVelocity() vx,vy = math2d.normalize( vx, vy ) vx,vy = math2d.scale( vx, vy, fixedRate ) self:setLinearVelocity( vx, vy ) end ) end obj:listen(“postCollision”)

Note: You use the word normal, but you’re trying to change the normal behavior of bouncing.  What you described can’t physically happen.  After a series of collisions, momentum will be lost if bounce is not 100% and if there is damping.  Also, objects will ‘exchange’ momentum.   

You are overriding this ‘normal’ behavior of physics, so this is going to take some tweaking to get it to behave they way you want.

Alternately, you could do this without physics, but then you have to know the math for physics like movement, and collision detection between various shaped bodies.

I’m copying and pasting your code and still its only moving up and down and side to side…

–SonicX278

I’ve got a better solution… posting in a minute.

Note: My solution above was a hint to get you moving in the right direction.  Not and end all solution.  You must experiment.

As you will see in a moment, I did and came up with a working solution, both similar and different from my suggestion.

Thanks!!!

–SonicX278

Downloadable example (written w/ SSK but you can convert to regular Corona): http://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2015/11/bouncy.zip

Solution in action:

https://www.youtube.com/watch?v=H2WXQUP6pL4&feature=youtu.be

Example coded with SSK (pay attention to the physics settings I used (second table in makers)):

-- -- Interesting bits start after this... -- local physics = require "physics" physics.start() physics.setGravity(0,0) local ballSpeed = 500 -- 100 pixels per second -- Walls local lw = newRect( nil, left, centerY, { fill = \_B\_, w = 40, h = fullh, anchorX = 0 }, { bodyType = "static", bounce = 1, friction = 0 } ) local rw = newRect( nil, right, centerY, { fill = \_B\_, w = 40, h = fullh, anchorX = 1 }, { bodyType = "static", bounce = 1, friction = 0 } ) local tw = newRect( nil, centerX, top, { fill = \_B\_, w = fullw, h = 40, anchorY = 0 }, { bodyType = "static", bounce = 1, friction = 0 } ) local bw = newRect( nil, centerX, bottom, { fill = \_B\_, w = fullw, h = 40, anchorY = 1 }, { bodyType = "static", bounce = 1, friction = 0 } ) local enterFrame = function( self ) local vx,vy = self:getLinearVelocity() vx,vy = normVec( vx, vy ) vx,vy = scaleVec( vx, vy, ballSpeed ) self:setLinearVelocity( vx, vy ) end local function newBall( x, y, angle ) local ball = newCircle( nil, x, y, { radius = 25, fill = randomColor(), stroke = randomColor(), strokeWidth = 2 }, { bounce = 1, friction = 0, isFixedRotation = true } ) local vec = angle2Vector( angle, true ) vec = scaleVec( vec, ballSpeed ) ball:setLinearVelocity( vec.x, vec.y ) ball.enterFrame = enterFrame listen( "enterFrame", ball ) end for i = 1, 25 do timer.performWithDelay( (i-1) \* 500, function() newBall( centerX, centerY, mRand(0,359) ) end ) end

Thanks so much! Is it hard to covert? I’m trying to keep this as simple as possible so newbies can understand it… And I’m not on my pc right now so I can’t check out the code my self…

–SonicX278

This solution is a bit of overkill.  You can further modify the enterFrame() listener to only change velocity if it below target velocity by a specific factor.  That way it isn’t change velocity every frame like now.

What do you mean trying to keep simple for newbies?  Isn’t this for your personal project?

If you’re asking for help making instructional materials, please mention that next time.  I have a policy of not helping write other’s instructional materials or templates.  That’s just letting me do the heavy lifting.  I’m not very keen on that.

I help here to help individuals, and have that help visible and useful to others (here in the forums) later.  I don’t help here so others can take my code and convert it into new instructional materials posted elsewhere for free or a fee. 

As far as the question, “Is it hard to convert”… you should try before asking, but this is the essence of the conversion you need to do:

This in SSK:

newRect( nil, left, centerY, { fill = \_B\_, w = 40, h = fullh, anchorX = 0 }, { bodyType = "static", bounce = 1, friction = 0 } )

equals this in ‘pure’ Corona:

local centerX = display.contentCenterX local centerY = display.contentCenterY local left = centerX - display.actualContentWidth/2 local right = centerX + display.actualContentWidth/2 local top = centerY - display.actualContentHeight/2 local bottom = centerY - display.actualContentHeight/2 local tmp = display.newRect( left, centerY, 40, display.actualContentHeight ) tmp.anchorX = 0 tmp:setFillColor( 0, 0, 1 ) physics.addBody( tmp, "static", { bounce = 1, friction = 0 } )

SSK newRect

Parameters of SSK newRect( group, x, y [, renderParams [, bodyParams] ] )

  • (required) group to insert object into (defaults to current stage if set to nil as I did above)
  • (required) x, y 
  • (optional) renderParams - Table containing named parameters for render settings.
  • (optional) bodyParams - Table containing physics settings.  If not passed, object will NOT have a body.  Pass a empty table for a ‘default’ body.

Ahh I see … No it’s for me but a friend of mine that’s just starting corona wants this… And I haven’t tried ssk so I can’t really explain what’s happening and how it works… But thanks alot!

–SonicX278

Re: helping a friend.  Ah, that is OK, and good to know.  Thanks for the clarification.

Just be aware.  SSK code is very easy to read as long as you already know how to write the pure equivalent.

Compare my two samples above and you’ll see the ‘common DNA’.

The SSK builders (newRect, newImageRect, etc.) are just parameterized modules that construct objects using pure Corona based the passed parameters.

Oh i see… 

Well thanks for all the help and you time!

–SonicX278

One last note.  I will mostly be using SSK from now on to write complex examples.

Why?  Well, as I said.  It is easy to read and grok the concepts as the syntax is very terse.  That way people can fit the example in their heads faster.

Also, as you can see from the side-by-side comparisons… writing pure Corona takes too dang long (compared to one line of SSK based code).  That is what SSK is for.  To speed up my coding.

Cheers,

Ed

Hey! So i have been trying to convert it to just Corona and Lua but i just cant figure out how to do the ssk stuff… Is it possible for you to help?

Here what i have for far…

local ballSpeed = 500 -- 100 pixels per second local lw = display.newRect( display.contentCenterX - 450, display.contentCenterY, 40, 600 ) physics.addBody( lw, "static", { bounce = 1 }) local rw = display.newRect( display.contentCenterX + 450, display.contentCenterY, 40, 600 ) physics.addBody( rw, "static", { bounce = 1 }) local tw = display.newRect( display.contentCenterX, display.contentCenterY - 300, 900, 40 ) physics.addBody( tw, "static", { bounce = 1 }) local bw = display.newRect( display.contentCenterX, display.contentCenterY + 300, 900, 40 ) physics.addBody( bw, "static", { bounce = 1 }) local enterFrame = function( self ) local vx,vy = self:getLinearVelocity() vx,vy = normVec( vx, vy ) vx,vy = scaleVec( vx, vy, ballSpeed ) self:setLinearVelocity( vx, vy ) end local function newBall( x, y, angle ) local ball = display.newCircle( x, y, 25 ) physics.addBody( ball, { radius = 25, bounce = 1 }) ball.isFixedRotation = true local vec = angle2Vector( angle, true ) vec = scaleVec( vec, ballSpeed ) ball:setLinearVelocity( vec.x, vec.y ) ball.enterFrame = enterFrame ball:addEventListener( "enterFrame", ball ) end local timer = timer.performWithDelay( 1, function() newBall( display.contentCenterX, display.contentCenterY, mRand(0,359) ) end, 1 )

Thanks!

Or should i just stick with the math2D plugin? Is it easier? Id still like to know how to do it with just pure corona lua.? 

Thanks!

I tried getting it work work with just the math2d plugin but no luck…

–SonicX278