Need help with math - reflection vector calculation

Hi, I am trying to manually implement ricochet effect, cannot use physics for this one.

I need to calculate reflection vector of a projectile from collision point.

So far I am able to get my collision point, normal and ray are wrong.

I feel I am getting close, but the angles are wrong (reverse, actually) since my math skills appear insufficient to successfully translate online examples.

I am referring to the SO post

I’d appreciate if someone helped me to fox this.

Attached is the example project and relevant code is below.

local function onCollision(event) local obj1 = event.object1 local obj2 = event.object2 local ball local shot if (obj1.name == "ball") then ball = obj1 shot = obj2 else ball = obj2 shot = obj1 end -- this is a collision point local shotX = shot.x local shotY = shot.y - shot.height / 2 local marker = display.newRect(g, shotX, shotY, 4,4) marker:setFillColor(1,1,0) -- reference URL: https://stackoverflow.com/questions/30970103/2d-line-reflection-on-a-mirror -- get ball surface normal vector local nY = ball.x - shotX local nX = ball.y - shotY local nLength = math.sqrt(nX \* nX + nY \* nY) nX = nX / nLength nY = nY / nLength local mLine1 = display.newLine(g, shotX, shotY, ball.x, ball.y) mLine1.strokeWidth = 2 mLine1:setStrokeColor(0.5,1,0) local marker2 = display.newRect(g, ball.x + nX\*40, ball.y + nY\*40, 4,4) marker2:setFillColor(0,0,1) -- the problem is here, most likely. local rayX = (shotX - gun.x) - shotX local rayY = ( shotY - gun.y) - shotY -- local rayX = shotX - shotX -- local rayY = shotY - shotX local marker3 = display.newRect(g, rayX, rayY, 6,6) marker3:setFillColor(1,0,1) print("RayXY: "..rayX.." "..rayY) local dotProduct = (rayX \* nX) + (rayY \* nY) local dotnX = dotProduct \* nX local dotnY = dotProduct \* nY local reflRayTipX = shotX - (dotnX \* 2) local reflRayTipY = shotY - (dotnY \* 2) local mLine2 = display.newLine(g, shotX, shotY, reflRayTipX, reflRayTipY) mLine2.strokeWidth = 1 mLine2:setStrokeColor(0,1,1) -- housekeeping display.remove(shot) for i = #shots, 1, -1 do table.remove(shots, i) end end

I think I found solution using only information from link you provided from stackoverflow.com

Try

local function onCollision(event)                local obj1 = event.object1      local obj2 = event.object2             local ball     local shot          if (obj1.name == "ball") then       ball = obj1       shot = obj2     else       ball = obj2       shot = obj1     end          -- this is a collision point   local shotX = shot.x   local shotY = shot.y - shot.height / 2    -- Code below  based on https://stackoverflow.com/questions/30970103/2d-line-reflection-on-a-mirror   local blue   = { 30 / 255, 144 / 255, 255 / 255 }   local red    = { 255 / 255, 0 / 255, 0 / 255 }   local yellow = { 255 / 255, 255 / 255, 0 / 255 }   -- Line   local line = { x1=shot.x, y1=shot.y, x2=ball.x, y2=ball.y }   local startShotX, startShotY = gun.x, gun.y - gun.height / 3   -- Intersection point   local iX, iY = line.x1, line.y1   --  Tip of the ray    local rayTipX, rayTipY = startShotX + ( iX - startShotX ) \* 1.2, startShotY + ( iY - startShotY ) \* 1.2   local rayX = rayTipX - iX   local rayY = rayTipY - iY     -- Line normal   local normalY = line.y2 - line.y1   local normalX = line.x2 - line.x1   local normalLength = math.sqrt( normalX \* normalX + normalY \* normalY )   normalX = normalX / normalLength   normalY = normalY / normalLength   local dotProduct = ( rayX \* normalX ) + ( rayY \* normalY )   local dotNormalX = dotProduct \* normalX   local dotNormalY = dotProduct \* normalY   local reflectedRayTipX = rayTipX - ( dotNormalX \* 2 )   local reflectedRayTipY = rayTipY - ( dotNormalY \* 2 )   -- Draw lines   local normalLine = display.newLine( g, iX, iY, iX + normalX \* normalLength, iY + normalY \* normalLength )   normalLine:setStrokeColor( unpack( blue ) )   local rayLine = display.newLine( g, startShotX, startShotY, rayTipX, rayTipY )   rayLine:setStrokeColor( unpack( red ) )    local reflecteRayLine = display.newLine( g, iX, iY, reflectedRayTipX, reflectedRayTipY )   reflecteRayLine:setStrokeColor( unpack( yellow ) )     -- housekeeping   display.remove(shot)      for  i = #shots, 1, -1 do     table.remove(shots, i)   end   end

Note:

  1. I use 

    local normalY = line.y2 - line.y1 local normalX = line.x2 - line.x1

instead of 

local normalY = line.x2 - line.x1 local normalX = line.y1 - line.y2
  1. I use 2x2 rectangle as shot, 

  2. Collision point is not accurate. See screenshot. 

Screenshot from Simulator

oq9fqTH.jpg

ldurniat

ssk.math2d can help with a the circle intersection issue above.

https://roaminggamer.github.io/RGDocs/pages/SSK2/libraries/math2D/#segment-circle-intersect

@Idurniat: Thanks, it does work! Will study the code to understand it.

I think I found solution using only information from link you provided from stackoverflow.com

Try

local function onCollision(event)                local obj1 = event.object1      local obj2 = event.object2             local ball     local shot          if (obj1.name == "ball") then       ball = obj1       shot = obj2     else       ball = obj2       shot = obj1     end          -- this is a collision point   local shotX = shot.x   local shotY = shot.y - shot.height / 2    -- Code below  based on https://stackoverflow.com/questions/30970103/2d-line-reflection-on-a-mirror   local blue   = { 30 / 255, 144 / 255, 255 / 255 }   local red    = { 255 / 255, 0 / 255, 0 / 255 }   local yellow = { 255 / 255, 255 / 255, 0 / 255 }   -- Line   local line = { x1=shot.x, y1=shot.y, x2=ball.x, y2=ball.y }   local startShotX, startShotY = gun.x, gun.y - gun.height / 3   -- Intersection point   local iX, iY = line.x1, line.y1   --  Tip of the ray    local rayTipX, rayTipY = startShotX + ( iX - startShotX ) \* 1.2, startShotY + ( iY - startShotY ) \* 1.2   local rayX = rayTipX - iX   local rayY = rayTipY - iY     -- Line normal   local normalY = line.y2 - line.y1   local normalX = line.x2 - line.x1   local normalLength = math.sqrt( normalX \* normalX + normalY \* normalY )   normalX = normalX / normalLength   normalY = normalY / normalLength   local dotProduct = ( rayX \* normalX ) + ( rayY \* normalY )   local dotNormalX = dotProduct \* normalX   local dotNormalY = dotProduct \* normalY   local reflectedRayTipX = rayTipX - ( dotNormalX \* 2 )   local reflectedRayTipY = rayTipY - ( dotNormalY \* 2 )   -- Draw lines   local normalLine = display.newLine( g, iX, iY, iX + normalX \* normalLength, iY + normalY \* normalLength )   normalLine:setStrokeColor( unpack( blue ) )   local rayLine = display.newLine( g, startShotX, startShotY, rayTipX, rayTipY )   rayLine:setStrokeColor( unpack( red ) )    local reflecteRayLine = display.newLine( g, iX, iY, reflectedRayTipX, reflectedRayTipY )   reflecteRayLine:setStrokeColor( unpack( yellow ) )     -- housekeeping   display.remove(shot)      for  i = #shots, 1, -1 do     table.remove(shots, i)   end   end

Note:

  1. I use 

    local normalY = line.y2 - line.y1 local normalX = line.x2 - line.x1

instead of 

local normalY = line.x2 - line.x1 local normalX = line.y1 - line.y2
  1. I use 2x2 rectangle as shot, 

  2. Collision point is not accurate. See screenshot. 

Screenshot from Simulator

oq9fqTH.jpg

ldurniat

ssk.math2d can help with a the circle intersection issue above.

https://roaminggamer.github.io/RGDocs/pages/SSK2/libraries/math2D/#segment-circle-intersect

@Idurniat: Thanks, it does work! Will study the code to understand it.