I’m not sure if I can clarify this any more, but I’ll try. This is a breakdown of the code:
Some Helper Variables and Setting Up Physics
local cx = display.contentCenterX local cy = display.contentCenterY local fullw = display.actualContentWidth local fullh = display.actualContentHeight local left = cx - fullw/2 local right = cx + fullw/2 local top = cy - fullh/2 local bottom = cy + fullh/2 local physics = require "physics" physics.start() physics.setGravity(0,10) physics.setDrawMode("hybrid")
Locals Specific To Example Positions and Sizes
local size = 80 -- ALL OBJECTS ARE 80 x 80 local radius = 38 -- Radius of ball a little less than half of 80 so the shape fits visible part better -- This actually throws off a later calculation a little accuracy wise. local y0 = cy - 200 -- Position of top marker bottom local y1 = cy + 200 -- Position of block top local tween = (y1 - y0) - size -- distance between those two spaces, less the size of the ball local targetY = y0 + tween/2 + size/2 -- Where target (marker 2) should be placed. i.e. Marks where -- I want ball to bounce to (based on your post)
A function to create markers, block, ball, and set up bounce/restitution
local function createParts( x, text, restitution ) restitution = restitution or 1 local dropMarker = display.newImageRect( "rg256.png", size, size ) dropMarker.x = x dropMarker.y = y0 dropMarker:setFillColor( 1, 0, 0, 0.25 ) local targetMarker = display.newImageRect( "rg256.png", size, size ) targetMarker.x = x targetMarker.y = targetY targetMarker:setFillColor( 0, 1, 0, 0.25 ) local block = display.newImageRect( "corona.png", size, size ) block.x = x block.y = y1 physics.addBody( block, "kinematic", { bounce = 0 } ) local label = display.newText( text, block.x, block.y + 100, nil, 20) local ball = display.newImageRect( "rg256.png", size, size ) ball.x = x ball.y = dropMarker.y physics.addBody( ball, "dynamic", { bounce = restitution, radius = radius } ) return ball, block end
Two Examples That: Do not do what you want. (i.e. naive approaches)
-- Wrong local ball, block = createParts( cx - 225, "Wrong 1" ) local ball, block = createParts( cx - 75, "Wrong 2", 0.5 )
One Example That: You’d think would work (it doesn’t).
-- Close local restitution = 0.5 local ball, block = createParts( cx + 75, "Close: " .. restitution, restitution ) ball.first = true function block.collision( self, event ) local other = event.other if( event.phase == "began" ) then if( other.first ) then other.first = false else event.contact.bounce = 1 end end return false end; block:addEventListener("collision")
The collision listeners does this:
- First bounce where ball.first flag is true - Set flag to false
- All subsequent bounces - Change restitution value of ball to 50% before doing response calculation.
(Nearly) Perfect Solution
-- Perfect local restitution = 0.5 + radius/tween local ball, block = createParts( cx + 225, "Perfect: " .. restitution, restitution ) ball.first = true function block.collision( self, event ) local other = event.other if( event.phase == "began" ) then if( other.first ) then other.first = false else event.contact.bounce = 1 end end return false end; block:addEventListener("collision")
This is almost exactly the same as the ‘close’ example, but I calculated a value for bounce/restitution.
All physics objects are treated like points for the purpose of calculations. That means the true position and travel distance of the ball is based on it’s center, not the bottom. Thus, I have to adjust the restitution as follows:
50% restitution + radius / travel-distance
tween is the travel distance.
i.e. need to make it a little more bouncy because it isn’t falling as far as I need it for it to get enough energy.
This calculation is simplified by the fact that the target bounce-to position is directly in the center (of the drop position and the block).
It would be a a little harder if I allowed for arbitrary bounce target positioning.