Unrestrained 3D Motion

Started by
5 comments, last by alvaro 12 years ago
Hi,

I'm working on something like a space flight simulator. There is no gravity and no collisions in this simulator (for now). I've got the player's location_x, location_y, and location_z as well as the player's speed, yaw and pitch (I am currently not enabling any sort of roll, but I don't think roll would have any bearing on position calculations anyhow).

I'm having some problem calculating the player's new location based on the current speed, yaw and pitch. For a player that's only moving in two directions - for example, walking across a plane, I know the equation goes something like this:

location_x += ((float)Math.cos(Math.toRadians(yaw)) * speed);
location_y += ((float)Math.sin(Math.toRadians(yaw)) * speed);

But what is the proper set of equations for calculating location_z, and how do I take pitch into account?
Advertisement
In space, you don't necessarily advance in the direction that your spaceship is pointing, so yaw and pitch don't matter. Other than the position, you need a vector called "velocity", whose size is the speed.

Then you just update the position by adding the velocity times the time increment (i.e., the time duration of a frame).

In space, you don't necessarily advance in the direction that your spaceship is pointing, so yaw and pitch don't matter. Other than the position, you need a vector called "velocity", whose size is the speed.

Then you just update the position by adding the velocity times the time increment (i.e., the time duration of a frame).


Ok, that makes sense. I've created a velocity_x, velocity_y and velocity_z and those get added to the location_x, location_y and location_z each iteration through the game loop, which works very well. But, my original problem still stands, more or less.

How do I adjust velocity_x, velocity_y and velocity_z based on the current rotation_x, rotation_y and rotation_z of the player?

Basically, if the player is holding down the left mouse button, I want to accellerate the craft in the direction that the player is currently looking.
As alvaro said, you cannot presume that the ship is flying in the direction where it's currently pointing. Of course you could do it this way, after all you're creating a game and in games everything is possible (hell, most spaceship simulators have sound effects, which isn't possible in vacuum).

Anyway, I personaly would try something like this:

You have 4 vectors:
- position (where the ship is in the space)
- direction (given by yaw and pitch, tells you how to render the ship and is handy later, read on...)
- velocity (direction in which the ship is currently flying, in general case have absolutely no relation to the direction vector)
- acceleration created by thrust (explained later)

Position and velocity are quite simple, each frame you simply modify your position by velocity:
position += velocity * dt;
(Those are vectors and vector operations, dt is delta time - time between two frames.)

Direction can be changed by the player when he wants to rotate the ship. This wouldn't be so trivial if you wanted an accurate simulation, because a real ship would probably rotate by some small jets placed on the ship for this purpose and you would have to work with forces, rotational inertia of the ship etc. But I think you can just simplify it somehow and just rotate the ship in the corresponding direction when the player holds a key (or analog stick).

Acceleration is caused by the main engine (jet) of the ship. The magnitude of this vector is given by the actual power of the engine (controlled by the player) and the orientation of the vector is equal to direction. Simply, the engine is pushing the ship in the direction where the ship is pointing.
You apply the acceleration very easily (direction must be a unit vector):
acceleration = direction * power;
velocity += acceleration * dt;

Which should be before the previous line, so in fact:

acceleration = direction * power;
velocity += acceleration * dt;
position += velocity * dt;

That's quite it. Of course you have to add the code that computes direction based on the player's input.

Now think about it - you hold the power button for a while, so the ship flies in one direction. Then you stop power - the ship will go in straight line with a constant speed (nothing is slowing it down in space). Now the player can rotate the ship however he wants, but the ship will still go in the original direction, you can for example rotate the ship 180 degrees and it will be going "backwards". Now if you again apply power, the ship will accelerate in the actual direction (towards the "spike" of the ship, not towards the actual movement vector), so as a result it may start slowing down (if it really was 180 degrees) or just generally changing direction.
Slight modification of what Tom KQT said: I would describe the state of the spaceship as

  • Position
  • Velocity
  • Attitude (a.k.a. orientation)
  • Angular velocity

Position is a point (but you can use a vector instead, if it's not clear to you what the difference is), velocity and angular velocity are vectors and attitude is a rotation, which can be represented using three angles (e.g., roll, pitch and yaw) or a 3x3 orthogonal matrix or a quaternion. I strongly recommend using the quaternion.

Then at each frame I would compute two more vectors:

  • Acceleration
  • Angular acceleration

Updating the state (the four things in the first list) based on these two accelerations can be done in many different ways, but you should probably start with Euler integration and go from there.

Of course, you can throw any part of classical mechanics away and impose your own rules: It's your game. So you could just have position, speed and attitude, and compute your velocity as speed*attitude_applied_to(1,0,0) (attitude is a rotation, so you can apply it to a vector in model coordinates to get the direction in which it points after the rotation), which is the answer to your original question.
If I'm understanding you correctly, you're having trouble finding the x, y, and z components of a vector given its roll, pitch, and yaw?

You are actually a lot of the way there. If the vector is pitched by angle theta above the x-y plane, then no matter what its yaw is its x and y components are lower by a factor of cos(theta). You can see that by drawing a triangle with the the x and y parts of the forward vector as the base and the total forward vector as the hypotenuse.

The z component is unaffected by yaw; with similar trigonometric arguments you can see that it is just sin(theta) times the magnitude of the vector.

To sum up:

vector.x = vectorMagnitude*cos(yaw)*cos(pitch);
vector.y = vectorMagnitude*sin(yaw)*cos(pitch);
vector.z = vectorMagnitude*sin(pitch);

I hope that helps!
In other words: http://mathworld.wolfram.com/SphericalCoordinates.html

This topic is closed to new replies.

Advertisement