Questions regarding angles / maths

I finally got a working 90°-angle bounce. The problem is that it works only in one direction… How to check the angle of the impact and then set the velocity depending on it ? I feel lost.

vx, vy = ball:getLinearVelocity()

ball:setLinearVelocity(-vy, vx)

You want to pass either the pair (-vy, vx) or the pair (vy, -vx), depending on which side of the line your ball is.

Your line will have a normal pointing out of it at 90 degrees. You get this the same way: turn your line into a ray, (x2 - x1, y2 - y1), or (rx, ry) for short, then choose one of the two perpendiculars, say (-ry, rx). You can normalize this vector, although for this purpose it doesn’t matter. Now, you have another ray, the one from the impact point to part of your object (like the center; obviously not the part that impacted, or your vector will be 0-length  :slight_smile: ), so (center x - impact x, center y - impact y), or (dx, dy) for short.

You can use the dot product to find the angle between two vectors: cos(angle) = (vx * wx + vy * wy) / (length(v) * (length(w))

The cosine will be positive if the angle is less than 90 degrees, 0 if it’s exactly 90 degrees, negative if more than 90 degrees.

Going back to your case, if the impact-to-center array dotted with the normal is greater than 0, it’s on one side of the line, if it’s 0, it hit the line perfectly parallel, it’s on the other side of the line.

So something like:

local linex, liney = endx - startx, endy - starty local rx, ry = -liney, linex local dx, dy = centerx - impactx, centery - impacty if rx \* dx + ry \* dy \> 0 then object:setLinearVelocity(-vy, vx) -- Untested, may be backwards :) else -- just handle the 0 case here too object:setLinearVelocity(vy, -vx) end

The lengths will both be positive and thus can be ignored. You never actually use the cosine, except to formulate the solution.

Thank you for your answer, StarCrunch. But

I don’t understand why we have to check the collision side…

140711121709452112.png

Also, could you please explain me what’s the difference between linex, liney and dx, dy ? Are the second element’s coords useful in this problem ?

OK, I used a little workaround to solve this problem :

local side = event.selfElement --1\>Left 2\>Top 3\>Right 4\>Bottom local velX, velY = ball:getLinearVelocity() if side == 1 then --Left if velY \> 0 then ball:setLinearVelocity(velY, -velX) elseif velY \< 0 then ball:setLinearVelocity(-velY, velX) else ball:setLinearVelocity(-velX, -velY) end elseif side == 2 then --Top if velX \> 0 then ball:setLinearVelocity(-velY, velX) elseif velX \< 0 then ball:setLinearVelocity(velY, -velX) else ball:setLinearVelocity(-velX, -velY) end elseif side == 3 then --Right if velY \> 0 then ball:setLinearVelocity(-velY, velX) elseif velY \< 0 then ball:setLinearVelocity(velY, -velX) else ball:setLinearVelocity(-velX, -velY) end elseif side == 4 then --Bottom if velX \> 0 then ball:setLinearVelocity(velY, -velX) elseif velX \< 0 then ball:setLinearVelocity(-velY, velX) else ball:setLinearVelocity(-velX, -velY) end end

It checks the collision side, then bounces the ball with setLinearVelocity(velY, -velX) or setLinearVelocity(-velY, velX) depending on the side AND the velocity.

(linex, liney) are your thick black line, the thinner segment from it to the ball is (dx, dy), and the  thin line is a normal.

What did you mean by “works only in one direction”? I may have misunderstood what problem you were running into, or given you something too general. (Are all your walls only horizontal? Or horizontal and vertical?)

Also, I guess I should ask if physics.rayCast() / physics.reflectRay() would fit your use case, since going any further I’d mostly just be dumping the underlying math on you (more than I already have).

Edit: Never mind, I see you ninja’d me with the answer  :slight_smile: