69

I played around with it for a while, but I simply can't figure it out.

I made a tank that fires missiles, and when the missiles hit the walls, I want them to bounce off, but I want them to bounce off to the right angle.

Right now I haven't got any obstacles, the missiles just bounce off when they get outside the viewportRectangle I made.

Is the solution I'm looking for quite advanced?

Is there a relativly simple way to do it?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Moulde
  • 3,438
  • 4
  • 29
  • 38
  • 2
    This is a problem for which the solution would probably become immediately obvious if you go play a game of pool. – smartcaveman Jun 18 '15 at 02:34

10 Answers10

205

You might think that because your walls are aligned with the coordinate axes that it makes sense to write special case code (for a vertical wall, negate the x-coordinate of the velocity; for a horizontal wall, negate the y-coordinate of the velocity). However, once you've got the game working well with vertical and horizontal walls, probably the next thing you'll think is, "what about walls at arbitrary angles?" So it's worth thinking about the general case from the beginning.

In the general case, suppose your missile has velocity v and hits a wall with surface normal n.

Missile with vector v about to obliquely hit a wall with surface normal n.

Split v into components u perpendicular to the wall and w parallel to it.

Right-angled triangle with hypotenuse for v, short side u parallel to wall and long side w parallel to wall.

Where:

u = (v · n / n · n) n
w = vu

Here, v · n is the dot product of the vectors v and n. See the link for an explanation of how to compute it. The dot product n · n evaluates to the square of the length of the normal vector; if you always keep your normals in the form of unit vectors then n · n = 1 and you can omit the division.

After bouncing, the component of motion parallel to the wall is affected by friction f, and the component perpendicular to the wall is affected by elasticity, which can be given in the form of a coefficient of restitution r.

So the velocity after the collision is v′ = f wr u. In a perfectly elastic, frictionless collision, v′ = wu; that is, the motion is reflected about the normal at the point of collision, as in the diagram given in Bill's answer.

This approach works just the same in three dimensions too.

(Obviously this is a very simplified notion of bouncing; it takes no account of angular momentum or deformation. But for many kinds of video games this kind of simplification is perfectly adequate.)

Gareth Rees
  • 64,967
  • 9
  • 133
  • 163
  • 3
    I agree that starting with the special-case coding for vertical and horizontal walls is the wrong way to go. It's not a stepping stone to the correct route, but is instead a dead-end path. – Adam Kane Sep 15 '09 at 18:00
  • Hey guys, this is an awesome explanation, but I think it has a bug. Shouldn't it be u = -n ( v.n / n.n )? After all, u is in the reversed direction of n. – nullspace Mar 16 '11 at 23:51
  • 2
    Am i the only one getting confused with the usage of v.n, instead of using v·n ? When i read n.n, my brain just exploded; thinking a normal had an element called normal. (im used to c++ too much?). – Rookie Dec 14 '12 at 15:10
  • To calculate surface normal n see this question: http://stackoverflow.com/questions/1243614/how-do-i-calculate-the-normal-vector-of-a-line-segment/ –  Feb 04 '16 at 21:40
  • Thank you soo much, this worked perfect. If anyone else is wondering, you can do `ux = (dotproduct(v,n)) * n`, `uy`, `wx` and `wy`. – Ajay Dec 04 '16 at 07:11
  • excellent explanation. One query; When you hit a line it has two normal's....is there a good trick to knowing what one to use as n? (Visually its obvious, but I am thinking for code here) – darkflame Jan 08 '17 at 16:05
  • @darkflame: If you can tell that an object hit a wall, then you can also tell which side of the wall it hit. – Gareth Rees Jan 08 '17 at 19:36
  • I'm probably missing the obvious but I worked out where the hit happened with just a algorithm for detecting where two lines will cross. That just gave me the point on a (2d) line - no side involved there. In code my known information is start and end point of line hit, velocity of object moving and the point it hit on the line. I *think* the correct normal to pick is always the one with the opposite sign in x or y to the object moving. – darkflame Jan 08 '17 at 23:16
71

I think an easier way to do this is to use the velocity of the missile instead of calculating angles. Say you have a missile that has xVelocity and yVelocity to represent its movement horizontally and vertically. Those velocities can be positive or negative to represent left, right, up, or down.

  • If a missile hits a top or bottom border reverse the sign of the yVelocity.
  • If a missile hits a left or right border reverse the sign of the xVelocity.

This will keep the movement in the opposite axis the same.

Borrowing the image from ChrisF's answer, let's say the missile starts out at position I.

Angle of Reflection

With the xVelocity and yVelocity both being positive (in 2D graphics right and down are typically positive) the missile will travel in the direction indicated. Let's just assign values of

xVelocity = 3
yVelocity = 4

When the missile hits the wall at position C, its xVelocity shouldn't change, but its yVelocity should be reversed to -4 so that it travels back in the up direction, but keeps going to the right.

The benefit to this method is that you only need to keep track of a missile's xPosition, yPosition, xVelocity, and yVelocity. Using just these four components and your game's update rate, the missile will always get redrawn at the correct position. Once you get into more complicated obstacles that are not at straight angles or are moving, it will be a lot easier to work with X and Y velocities than with angles.

Community
  • 1
  • 1
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
  • I use the angle of the missile to make it go forward. using Math.Sin and Math.Cos. I had problems understanding the other way, using velocity, like in the XNA example with the canonballs. So all i have to change is the angle of the missile, then it will go forward by itself. – Moulde Feb 21 '09 at 14:28
  • Just good physics. A VERY nice illustration. +1 just for that, since a picture is worth 10K words. I'm doling out micropoints, so it's 0.001 per word saved. 8) – duffymo Feb 21 '09 at 14:39
  • 35
    This only works if all your walls are aligned to the coordinate axes, and even then you need separate case for vertical and horizontal walls. It's probably easier to get it right in the general case. – Gareth Rees Feb 21 '09 at 15:19
  • 1
    No, it isnt. In the general case what you have to do is align your vectors using some trigonometry so that the wall becomes horizontal or vertical for the sake of your calculation, then do this calculation, and convert it back. It's onyl 2-4 more trig calcs, but not easier. – Karl Feb 21 '09 at 15:33
  • @Gareth: You're right this only works for the borders and for walls that are aligned with the borders. I was only answering the question that was asked, which is much easier than the general case. – Bill the Lizard Feb 21 '09 at 15:46
  • 1
    @Karl: No trigonometry is required! – Gareth Rees Feb 21 '09 at 15:47
  • 1
    Of course, you can easily adapt this to work for objects at different angles that are stationary or moving. Just use the velocities of both objects in a collision to calculate the new velocities of each. – Bill the Lizard Feb 21 '09 at 16:03
8

I've had this problem, the only way I found was separating the axes of collision!

Try it:

x += velocity * Math.cos(angle * Math.PI /180);
y += velocity * Math.sin(angle * Math.PI /180);

if (x < 0 || x > canvas.width) {
     angle = 180 - angle;   
}
else if (y < 0 ||y > canvas.height) {
     angle = 360 - angle; 
}

I hope this helps you!

  • Not the ideal general-case solution, however it was precisely what I needed right now (reflecting off the canvas edges). For some reason I couldn't get my brain to arrive at this solution on its own. – Draco18s no longer trusts SE Jun 03 '16 at 17:56
8

For perfect particles (& light) the angle of reflection is equal to the angle of incidence, as illustrated by this diagram (from commons.wikimedia.org).

Angle of Reflection

The Wikipedia page on reflection is quite good at explaining how it works.

It's a little bit more complicated when you take into account the elasticity and materials of the object and the obstacles, but this is probably good enough for most applications.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
6

As an aside to the specific physics question you are asking, I would recommend the book "Beginning Math and Physics for Game Programmers" by Wendy Stahler. I found it quite useful for my game/physics programming projects.

The code that accompanies the book is C++ but if you know C#, it would be pretty easy to make the conversion.

Have a good one!

itsmatt
  • 31,265
  • 10
  • 100
  • 164
4

180-a will not work in all instances, unless you are merely working a bounce on a top surface when X is increasing.

One direction to head is the XNA forums or pick up XNA sample code. It is C# and it is for building games. I am not stating you want to build your games in XNA, but it is a great tool, and it is free.

Gregory A Beamer
  • 16,870
  • 3
  • 25
  • 32
  • It is XNA im using. And yes, there is a problem.. When firering missiles at the left and right border of the window, the missiles reflect properly, but when shooting at the bottom or top border of the window, i can see the reflect, just not the right angle. – Moulde Feb 21 '09 at 14:39
3

a = 2w - b

where:
a => resulting angle
w => wall or floor or ceiling angle
b => ball angle

This is what I come up after trying to find the simplest formula for computing just the resulting angle of ball bouncing the walls, ceiling and floor. The result could go beyond +360 or -360 degrees but they are still equivalent angle.

For example if the ceiling angle is 270deg and the ball angle is 30deg, the resulting angle is 510deg which is equivalent to +150deg or -210 deg. If you'll use 90deg for the ceiling instead of 270deg, the result is still 150deg.

d_air
  • 631
  • 1
  • 4
  • 12
1

Not complicated at all - pseudo-code:

angleObjectHitWall = a;
bounceAngle = 180-a;

Of course this is a very simple calculation, and is totally irrelevant once you start to take into account factors such as material, gravity, walls which aren't straight, etc...

Yuval Adam
  • 161,610
  • 92
  • 305
  • 395
0

This is really a physics question, so if you are not a physicist (and since you are asking this question, I'm going to take it that you are not) it will require a lot of reading and brainstorming to get it right.

I suggest reading this wikipedia entry to get the basic idea about the depth of your question.

If you only want to make it "look plausible" then I wouldn't worry about it too much and use Bill the Lizard's answer, however if you want to make it right you will have quite an adventure. Don't let this scare you tho! Good luck!

David Božjak
  • 16,887
  • 18
  • 67
  • 98
  • 1
    Unless he's writing a physics simulation engine, this has nothing to do with physics. OP just wants simple mirror reflection. – Davor Jan 17 '21 at 11:34
-5
if(!Collide(Missle, Mainchar)){
(Velocity.x)*-1;
(Velocity.y)*-1;
}

It works and is simple, good luck.

kittykittybangbang
  • 2,380
  • 4
  • 16
  • 27