Questions regarding angles / maths

Hello everyone, I know the answers to these questions are quite simple, but I’ve been scratching my head without finding them  :frowning:

Here are the two problems : 

1) Limit line length, getting new coordinates for the “cut” line

140710012743775209.png

2) How to simulate 90°-only bounces ?

140710013018721478.png

I hope the images are explicit enough, thank you in advance for your answers !

Hi Uly,

Google vector math and trigonometry to learn about this.

For problem 1, short answer, and I might be wrong because I’m not testing the code.

  • use lineAngle = math.atan2(y,x) to get the angle of the “long line” in radians.

  • then if your limited length is 100, the x component will be math.cos(lineAngle)*100, and the y component will be math.sin(lineAngle)*100

For problem two, to simulate the 90° bounce, switch the x-compenent for the y-component and vice versa!

Cheers,

Thomas

For the first problem I would use Vectors.

There are free LUA vectors libraries (or you might do some calculations by yourself.

-Make Vector from origin point to event.x,event.y

-If vector length longer then limit, normalize vector and multiply by length limit.

-Draw line

There you have it Uly: either use vectors, or go for the simple underlying trigonometry math that builds vectors.

t

Thank you for your answers, you solved my problem  :smiley: !

Concerning the second problem, I’m sorry but I don’t understand your answer, thomas6. How could I implement a x/y switching in Corona SDK ? In “preCollision” ?

I am not very much experienced in physisc. I assume in precollision you can get objects linear velocity.

object:getLinearVelocity()

It retutrns x,y component in pixels/s

Now in postcollision you apply force to object - x to y, y to x. 

You might need to prevent applying regular bounce forces of object

EDIT:

I think 

object:setLinearVelocity() is the function that need to be used to “bounce” object

Eh, that was a nice idea, but unfortunately it doesn’t work. Or maybe I haven’t implemented it correctly ?

What I did is :

onCollision = function( event ) if event.phase == "began" then local velX, velY = ball:getLinearVelocity() ball:setLinearVelocity(velY, velX) end end

What I get :

140710014625287151.png

Your logic will have to be a bit more complex because depending on which side you hit, you’ll have to set either X or Y to it’s negative value.

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:

Hi Uly,

Google vector math and trigonometry to learn about this.

For problem 1, short answer, and I might be wrong because I’m not testing the code.

  • use lineAngle = math.atan2(y,x) to get the angle of the “long line” in radians.

  • then if your limited length is 100, the x component will be math.cos(lineAngle)*100, and the y component will be math.sin(lineAngle)*100

For problem two, to simulate the 90° bounce, switch the x-compenent for the y-component and vice versa!

Cheers,

Thomas

For the first problem I would use Vectors.

There are free LUA vectors libraries (or you might do some calculations by yourself.

-Make Vector from origin point to event.x,event.y

-If vector length longer then limit, normalize vector and multiply by length limit.

-Draw line

There you have it Uly: either use vectors, or go for the simple underlying trigonometry math that builds vectors.

t

Thank you for your answers, you solved my problem  :smiley: !

Concerning the second problem, I’m sorry but I don’t understand your answer, thomas6. How could I implement a x/y switching in Corona SDK ? In “preCollision” ?

I am not very much experienced in physisc. I assume in precollision you can get objects linear velocity.

object:getLinearVelocity()

It retutrns x,y component in pixels/s

Now in postcollision you apply force to object - x to y, y to x. 

You might need to prevent applying regular bounce forces of object

EDIT:

I think 

object:setLinearVelocity() is the function that need to be used to “bounce” object

Eh, that was a nice idea, but unfortunately it doesn’t work. Or maybe I haven’t implemented it correctly ?

What I did is :

onCollision = function( event ) if event.phase == "began" then local velX, velY = ball:getLinearVelocity() ball:setLinearVelocity(velY, velX) end end

What I get :

140710014625287151.png

Your logic will have to be a bit more complex because depending on which side you hit, you’ll have to set either X or Y to it’s negative value.