Angles, how i hate them...
sicgamemaker

NEVER MIND! but let it remain, i do hate angles and trigs

Greyer

Soh Cah Toa
Then you'll never see the end
Dont yah knowa
Sin() is not a sin
cos shows the spirt within
and when you want to know the hypontose
take the square and hand a noose
Pathagragram was a cool guy
so next a triangle has you all up in a bunch
open up a bag of chips and take a munch
--I'm a poet (and i dident know it)

23yrold3yrold
```SOH CAH TOA

Some     Old     Hippie
Caught   Another Hippie
Tripping On      Acid
```

There's another with "Old Hags" but I forget it ....

Steve Terry

hahahahhahahahhhaahhahahhahahhahahahaha

Marty Dill

That brings back memories ...

gillius

People always mention sohcahtoa or whatever it is but I never learned that one. I guess I learned a different one, which I haven't heard from other people:

Oscar Had A Heap Of Apples:

OH AH OA

sin = O/H
cos = A/H
tan = O/A

O = opposite edge
H = hypotenuse

Thomas Harte

I hate to put a dampener on things, but the number of times even a program with 'perfect' physics actually calculates the angle between anything is zero. And certainly the number of times any of that stuff they taught you during the first few years of school about soh cah toa isn't very useful in either the real or programming worlds . . .

Derezo

I found that when I first started programming.. 'soh cah toa' actually made things worse! I was trying to do the stuff that was already done for me, then add it here.. subtract it here... and voila! A big mess!

Shawn Hargreaves

I think angles are very rarely a good idea. They are the obvious way to store orientation because they are what you get taught in school, but vectors are almost always easier and more efficient and more flexible. Especially in 3D (it wasn't until I'd been doing commercial games for several months that I figured out how much a pain it was to use angles for everything!) but even in 2D vectors are nice.

If you store all your orientations and positions and speeds as vectors, it becomes incredibly easy to convert between any of them (just a few adds and subtracts). And you can do much more interesting physics type stuff without too much hassle, for instance bouncing off walls is just a dot product to reverse the momentum, plus maybe a multiply if you want to absorb some energy during the collision response. That kind of thing would be a total nightmare to do with an angle+speed type respresentation.

And learn how dot products work: that is the most useful basic operation you can possibly have, as almost anything can be done in terms of it.

A good C++ vector class is highly recommended, so you can add/subtract/scale vectors as simple data types. And overload operators for some of the more useful operations (I use ^ for cross product, | for dot product, and unary ~ for normalize). There's one in my Speedhack entry that you could use as a starting point...

sicgamemaker

i guess i should learn vectors? point me in a good direction and ill go learn about em

closest i come is an angle and a velocity...

Thomas Harte

There isn't much to learn about vectors, they are very simple. A vector is an ordered n-tuple. In geometric space, when people say 'vectors' they usually mean something of the form :

(x, y [, z])

Where the components are quantities to move parrallel to the predefined set of axis :

(1, 0 [, 0])
(0, 1 [, 0])
[(0, 0, 1)]

The most interesting thing one can do between two vectors in the general case is the dot, or scalar, product. Which maps two vectors to a scalar, like this :

(a, b [, c]).(d, e [, f]) = a*d + b*e [+ c*f]

The scalar has the property that it is :

|(a, b [, c])||(d, e [, f])|cos(angle between)

Where || are used to mean 'length of'. Which also means that it is a way of finding out how far either vector travels in the direction of the other, the result being in multiples of the length of the other.

There is also the 'cross' product, but this isn't so interesting since it is defined only in 3 and 8 dimensions. It takes two vectors and gives one that is perpendicular to both, by :

(a, b, c)x(d, e, f) = ( (b*f - e*c), (c*d - f*a), (a*e - d*b) )

Finally, commonly people like to make vectors unit length, principly because it makes like easier in the dot product. This is easy, you just get the total vector length (using Pythagoras) and divide each component by it.

And that is nearly all most programmers know about vectors. The only extra bit of information is that it is very useful to store planes (or lines in 2d) in the form 'normal vector & distance from the origin along normal vector', since then you can dot product away without any adaption.

Shawn Hargreaves

2d vector: a pair of values, eg. (x, y)
3d vector: a trio of values, eg. (x, y, z)

So all positions are vectors. Also all directions can be stored as vectors.

Given the points A and B, the direction from A to B is the vector B-A. Call this direction vector D. Then you can start doing basic algebra with them, eg. B = A+D (this is where the C++ vector class comes in handy as it lets you write such things directly).

The direction vector D contains both direction and distance information. You can extract the distance using Pythagoras:

dist = d.magnitude() = sqrt(d.x*d.x + d.y*d.y)

Once you have that, you can normalize d:

d.x /= dist;
d.y /= dist;

Or if you have good C++ classes:

d /= dist; or
d.normalize(); or
d = ~d;

This will give you a unit vector, which holds only direction information. It points in the same direction as the original D, but has length=1. Unit vectors are especially handy for using with dot products...

The dot product, a | b = a.x*b.x + a.y*b.y. If a and b are both unit vectors, this gives the cosine of the angle between them. If only a is a unit vector, this tells you how much of vector b lies along the direction of a. Which is a lot more useful than it might seem! It will be zero if the lines are at right angles, positive if they are in the same direction, negative if they are in opposite directions.

An example of a simple vector based physics system:

Vector pos(0, 0);
Vector vel(0, 0);
Vector dir(0, 0);

pos += vel;

// apply air resistance
vel *= 0.9;

// apply gravity
const Vector gravity(0, 0.1);
vel += gravity;

// apply thrust
if (firing thruster)
vel += dir;

// turn by angle
dir = Vector(dir.x*cos(ang) - dir.y*sin(ang),
dir.y*cos(ang) + dir.x*sin(ang));

Which is probably very similar to stuff you are already doing, as a lot of vector math is just common sense!

Let's add a bit of collision. Assume we have a wall defined by an infinitely long line (if the line has fixed ends the same principle applies but needs a few extra checks). You can store this line as a vector holding any arbitrary point on the line, and another unit vector holding the normal of the line (the normal is just a vector at 90 degrees to the direction of the line).

Say L is a point on the line, N is the normal, and you want to check for collision of a point P. Work out:

// direction from point to line
Vector d = L - P;

// dot the direction with the line normal
float dot = d | N;

// which side of the line are we on?
if (dot > 0)
// collision!

Ok, let's try bouncing off the line, rather than just stopping dead after we hit it. For that, we want to reverse the amount of our velocity that was heading towards the surface, but leave the amount of velocity that was sideways on to the surface alone. Really easy to do with dot products:

// how much velocity was towards the surface?
float dot = vel | N;

// recoil away from the surface by that amount
Vector recoil = dot * N;

// apply recoil. One of it will cancel out
// the movement towards the surface, and two
// of it makes us bounce back away from it.
vel -= recoil*2;

You can really easily extend this to support non-elastic collisions, where the surface absorbs some amount of your energy. Either change the last line above to:

vel -= recoil*1.5;

to absorb half the energy, or for a surface that also absorbs sideways motion:

vel = (vel-recoil*2) * 0.5;

The really great thing about vectors is that they work pretty much the same in 2d and 3d. Working with angles is ok but sometimes a bit complicated in 2d, but becomes a million times worse if you try to extend it into 3d, while vectors are equally simple in either.

sicgamemaker

wow thats a lot of stuff... yo uthink id be able to pick that crap up easily being in calculus 2, but it seems strange to me...
so tell me this:
i have a character object , and i dont want to use angles any more
do i need to store several vectors for him?
ie. direction, velocity, point?

Damyan Pepper

Yup - I normally store the velocity, the position and the front vector. If you're in 3D then also a right vector. You can then work out an up vector by crossing the front and right.

Be sure that you keep your direction vectors normalised!

Cross products only really make sense in 3D:

vc is the cross product of v1 and v2:

vc.x = v1.y * v2.z - v1.z * v2.y
vc.y = v1.z * v2.x - v1.x * v2.z
vc.z = v1.x * v2.y - v1.y * v2.x

I think it is quite standard to use the ^ operator in C++ for this.

So, (v1 ^ v2) gives you the vector perpendicular to v1 and v2. This only works if v1 and v2 are both normalised.

Shawn Hargreaves

Ignore Damyan. In 3D, sensible people always store the front vector and up vector, and generate the right vector with a cross product. Only a crazy man would suggest storing front and right and regenerating up!

Actually it makes no difference: you could store all three if you wanted. But there is no need as given any two of front, up, and right, you can recalculate the other one whenever needed with a cross product.

The problem with storing all three is that it only makes sense for them to be at right angles to each other (otherwise your object would be in some weird squashed universe with dimensions at funny angles :-) but even if they start out at right angles, over time as you rotate the object, rounding errors are likely to end up with them getting misaligned. So at the end of each frame, it is worth renormalising everything to make sure all your vectors are perpendicular, eg, if you store front and up:

front = ~front;
Vector right = front ^ up;
up = ~(right ^ front);

(assuming ~ = normalize and ^ = cross product)

This will give you a new up vector that has been corrected to make sure it is exactly 90 degrees from the front vector.

Incidentally, Damyan is also wrong in saying that vectors have to be normalised for cross products to work: it's just that if they aren't normalized, or if the input vectors aren't 90 from each other, the result won't be a unit vector (so you have to re-normalize it).

Don't you feel stupid now Damyan? :-)

In 2D you don't need any of that: just a single front vector is enough to encode a complete orientation. Plus position, obviously, and maybe velocity.

Thomas Harte
Quote:

In 2D you don't need any of that: just a single front vector is enough to encode a complete orientation. Plus position, obviously, and maybe velocity.

A whole post of pettiness for you:

It depends what you want to do. Even in general case engines, you will usually [numerically] integrate acceleration to get velocity, and integrate that to get position. Note to those scared of maths - this :

vel += acc;
pos += vel;

is actually an approximate integration using the same simple observation as Euler made many centuries ago about graphs, but taking the 'step size', often called h, to be 1.

However, my childishness makes me point out - there is no point storing velocity if you don't intend to make your objects move, and if they are moving you are probably storing a list of the forces acting upon the body also. So thats something else you want to store.

Damyan Pepper

I guess I've had one of those days, Shawn.

BTW, are you sure that cupid is frame rate compensated?

Also, on the subject of euler integration, some of you may be interested to have a look at the string code in cupid, and grabbing hold of the paper that is linked at the top of heart_trails.cpp that describes a really neat and simple way of doing physics without all the tedious mucking around with forces, inertia tensors and other nastiness.

sicgamemaker

wow, im really confused... id probably get it if you showe dme an example of these few things( all i do is 2-D im not concerned with 3d yet, all it does is confuse me :

if i have position vector A and velocity vector B, to move him would be A+B, the result of which is my new position?

how would i go about rotating a vector? say i have a sprite pointing straight up and i want him to rotate 128 (fixed numbers ) degress ?

how would i clip a vector agaisnt a vector? like tell where, and when a collsion occured?

what does normalizing do, why would i want to do it, and how is it done, and how does it effect the numbers stored in the vectors?

tehre wre more quations .. confusions i mean? that i may need answers for thanks for he hwelp though

Bob

Damyan: That link 404s on me
You wouldn't happen to have the paper on hand (or at least another link to it)?
Thanks.

Peter Wang

I'll answer the easy one :-) Normalising is turning a vector into a unit vector, i.e. a vector of length 1. (divide each component of vector v with the magnitude of v) If that's wrong, I'll look like a fool.

This thread has been really useful. If I had read this last year maybe I would have paid attention in class.

sicgamemaker

wow, that stuff seems to be over my head

Damyan Pepper

It would be worth reading through it - it does end up giving some source code that pretty much works.

If you have position A and velocity B, then yes, A+B gives you the new position. This is basically Euler integration - so if you read anything that goes on about Euler integration then don't be scared. (I was so pleased when I realised that!)

To rotate an arbitrary vector, F by ang degrees:

newF.x = F.x * cos(ang) - F.y * sin(ang)
newF.y = F.y * cos(ang) + F.x * sin(ang)

I'd also normalise it after that, just to be sure...although Shawn'll probably complain that I normalise too much!

Shawn has also just pointed out that another neat way to deal with rotations is to just add some amount of the right vector and normalise again:

newF = ~(F + right*0.2);

This is harder to control though!

I'm not sure what you mean by clipping a vector against a vector. There's a whole bunch of collision detection stuff in cupid, colliding circles against lines etc. that might be useful.

Shawn Hargreaves

Thomas Harte writes:
> It depends what you want to do. Even in
> general case engines, you will usually
> [numerically] integrate acceleration to
> get velocity, and integrate that to get
> position.

But acceleration is often a constant, so it's not part of the data you'd bother storing. Even when it is variable, acceleration rarely has state that needs to persist from frame to frame, eg. in MotoGP the acceleration force is a function of the engine revs, torque, current gear, current speed, and so on.

> Note to those scared of maths - this :
>
> vel += acc;
> pos += vel;
>
> is actually an approximate integration

I hate the term 'integration' because it makes the issue seem far more complicated than it really is! It's pretty rare for you to need anything more than the simple Euler integration you give above, and although this is of course just a linear approximation of a proper calculus integration, it's a lot easier to visualise if you just think of it as adding a load of forces together!

> However, my childishness makes me point
> out - there is no point storing velocity
> if you don't intend to make your objects
> move

Very true :-)

----------------

Damyan Pepper writes:
> BTW, are you sure that cupid is frame rate
> compensated?

Haha.

(to explain: about halfway through Saturday George complained that the ship turned more slowly if you were near the bottom of the level. After trying to blame Damyan for it, it turned out that I had very carefully adjusted the render function to run at a fixed framerate, while the update just ran as fast as possible in whatever time was left. Oops!)

----------------

Peter Wang writes:
> This thread has been really useful. If
> have paid attention in class.

Nobody seems to teach vectors properly. Or at least not in ways that make them seem useful for solving real world problems.

When someone says "a dot b gives the cosine of the angle between the two vectors, as long as they are unit vectors", that doesn't seem especially handy. When I first heard this I just filed it away as "I'll remember that in case I ever need to know the cosine of the angle between two unit vectors". And I never needed to know that.

It is only when you realise that dot product tells you how much of one vector lies in the direction of another that it starts to be useful. It turns out that about 90% of what you do in games and graphics can be expressed in terms of dot products, which is why things like the NVidia vertex shader processor or PS2 vector units are basically just really fast dot product evaluators!

When I first started working at Probe, I was doing some flags in the crowd for an N64 football game, and spent about three days working out loads of trig calls to rotate a polygon so it would always face towards the camera. I got it working in the end, but it required about 10 sin/cos calls, two tangents, one inverse tangent, multiple square roots, and a huge amount of head scratching. I couldn't decide whether to be pissed off or incredibly relieved when I started on ExtremeG, and Ash (the lead coder) explained how you can do the same thing using just a couple of dot products and one cross product!

Matt Smith

Ash Hogg? say Hi from me

Elias

Thanks for the link to that article, it really looks great

When I saw you were talking about Euler integration.. I remembered, some time back when I tried making a simple car game, someone (on comp.sci.physics i think) told me Euler integration can't be used because it takes too much CPU time when you want get things like sliding and skipping right. I forgot how the other technique is called he told me to use, but it was too complicated for me and I gave up on it. (it was called Runge-Kutta or Lagrange or somethinkg like that..) But now it seems, Euler integration (or the one mentioned in that article) is the best way after all, if even you people are using it
Anyway, when I find some time I'll read through that article again and see if I can apply it to my old car game..

Shawn Hargreaves

The physics for all our games at Climax are based on a library called Dyne, written by Chris Caulfield (who previously did the physics for Revolt). It is fairly accurate, but not as sophisticated as the Revolt physics, for instance Dyne doesn't handle stacking multiple objects on top of each other very well (but runs in far less CPU, which is more important :-)

Good game physics is a matter of getting a solid core (because it tends to feel nice if the behaviour is close to how the real world behaves), but then add lots of special case bodges over the top. For instance in MotoGP things like the wheelies and skids and spinning the rear wheel are total hacks added by George, nowhere near to being handled properly by the underlying physics layer, but these things are often the most fun and the bits that make people say the physics seems very realistic!

So don't be afraid to mix and match proper physics simulations with special-case behaviours, and don't believe people who insist you need to use all those stupidly complicated techniques (you may need them in some cases, but if a simpler method is adequate for your task, you may as well use it and save yourself the hassle and CPU...)

Matt Smith

If you've seen my Speedhack entry you'll know that

• I like angles

• I represent EVERYTHING as spheres, which will make physics easy. It will get complicated when I add sticks and polys tho

Angles have their uses for simple games, because in asm sin/cos are very cheap operations compared to the mul/div for normalising. In asm you have a table with a sine wave (cos uses the same table with a 90° phase shift) so you can turn an angle into a vector extremely quickly if you don't need high precision.

Paul Pridham

These conversations need to go into a FAQ.

Shawn Hargreaves

MattSmith writes:
> I represent EVERYTHING as spheres, which
> will make physics easy.

Rebounding off spheres is still much easier to do with vectors and dot products than it is with angles :-)

> Angles have their uses for simple games,
> because in asm sin/cos are very cheap
> operations compared to the mul/div for
> normalising. In asm you have a table with a
> sine wave (cos uses the same table with a 90°
> phase shift) so you can turn an angle into a
> vector extremely quickly if you don't need
> high precision.

So what? Multiplies and divides are cheap, and CPU manufacturers have spent the last five years or so concentrating on ways to make vector math fast. Plus you can't do inverse tangents as lookup tables, which you will need for anything more than very trivial trig calculations. For anything even approaching an interesting level of complexity (ie. with more than one single force acting on objects, or with collision against diagonal lines, or in 3D), a vector approach will be most efficient, and if your application is so simple that just one angle and lookup table trig is sufficient, it really doesn't matter if you can shave a few cycles off by using an integer lookup rather than a multiply because it's going to run plenty fast enough anyway. It's one thing to support slow machines, but optimising to avoid multiplies hasn't made sense since 286 days!

Bob
Quote:

Multiplies and divides are cheap,

Multiplies? Yes. Divides? Hell no
We're talking about a ratio of at least 38 in favor of multiplies, in both integer and floating point (ratio is even higher on integer).

Shawn Hargreaves

> Multiplies? Yes. Divides? Hell no
> We're talking about a ratio of at least
> 38 in favor of multiplies

They aren't cheap if you're counting cycles in a per-pixel inner loop, but everything is relative. In the context of a physics system, they are incredibly cheap compared to most of the other things you will be doing! (which is probably going to be limited by the number of square roots and possibly memory access for collision checking). It's still worth avoiding stupid numbers of divides, but I think taking things way too far if you design the whole system around that avoidance. You'd have to work pretty hard to make divides be the performance bottleneck.

Thomas Harte
Quote:

But acceleration is often a constant,

Linear acceleration due to gravity may be, but what about, e.g., angular acceleration due to gravity + an acceleration point on the body such as a jet pack or something?

Bob

I guess the lesson is: Shawn Is Always Right

Zaphos

"Bouncing off walls is just a dot product"? In my speedhack game (Balls) I used a rotation matrix to rotate the speed vector for my ball to the angle of the line it was colliding with, changed y to -y * some_fraction, and then used the inverse rotation matrix to convert back to the standard coordinate system. Is there a better way to do that?

sicgamemaker

see that... tahts the whole reason i havent messed with vectors...i dont understand a thing zaphos said

23yrold3yrold

Well, to be fair, he didn't say it to be understood. He just made a quick summary, knowing well and good that gurus like Shawn and Bob would understand

Bruce Perry

Zaphos: yep, vectors make it a whole lot easier. No rotation required. All you need is a vector (i.e. three numbers, (x,y,z), or two if you're in 2D) which points straight out of the surface you're bouncing off - that's a normal vector. Then it has to be normalised (x*x + y*y [+ z*z] = 1); you can do this by dividing each term by sqrt(x*x+y*y[+z*z]). Calculate the dot product of this normal vector and your velocity vector, and you should get a negative number. The fact that it's negative means the ball is moving into the surface (opposite the normal vector) rather than out. Its value indicates how fast, ignoring sideways velocity. Then you multiply it by the normal vector, subtract it from the velocity, and all of a sudden your ball isn't moving into the wall any more - it's moving along the wall. Subtract it again (or subtract it once but multiply by two first), and it's bounced!

I just explained the same thing as Shawn but slightly differently. Shawn's explanation is more formal, whereas mine's just rushed Still, I hope that clears things up.

Shawn Hargreaves

Like Ben said :-)

It's the same thing as Zaphos's matrix technique, just a lot less code if you do it with a dot product.

For a really simple example, take a look at arrow.cpp from my Cupid speedhack entry, lines 35+36. The collision check returns the normal of the barrier it hit, plus a distance value indicating how far we are on the wrong side of the barrier we are. Line 35 pulls the object back onto the correct side of the collision, and line 36 changes the velocity to make it bounce.

Thomas Harte

Returning to my own private strand of this conversation, what about the fairly common acceleration due to being attached to a spring - will anyone claim this is 'constant'?

Bob

Ok, constant acceleration doesn't apply in all cases obviously. However, it is constant in most game-related situations (unless your game involves a lot of springs...).

Damyan Pepper

I'm getting confused with all this constant acceleration stuff.

Surely a game with constant acceleration would be extremely dull!

George Foot

The main thing is that there's no accumulation of acceleration. Technically acceleration is the integral of jerk, but this isn't generally a useful way of viewing it -- in the real world, objects are influenced primarily by forces being applied, which map directly to acceleration. Translating that into the game world, it's far simpler to recalculate all forces applied to an object (including those due to springs, based on extension of spring) for each frame, and set the acceleration to that total (divided by mass, if applicable).

Technically it's also not sufficient to just add this stuff up -- you ought to be multiplying in some time deltas too -- but if your update loop runs at a constant rate and you'll never change that rate then this doesn't matter.

If you do want to change that rate, you want to do this:

```acc = force / mass;
vel += acc * dt + impulse / mass;
pos += vel * dt + extraction;
```

or if you're tracking momentum:

```momentum += force * dt + impulse;
vel = momentum / mass;
pos += vel * dt + extraction;
```

Zaphos

Shawn & Ben: Thank you kindly Looks all more pretty and such, your way.