Advertisement

Move The Player Along The Direction It Is Facing

Started by July 17, 2016 06:27 AM
5 comments, last by alvaro 8 years, 7 months ago

Hello folks,

I'm trying to build a flight model where the player's spaceship moves along the direction it is facing. What I'm doing right now is:

Considering my player gameobject as:


glm::vec3 position;
glm::vec3 angle;

Move forward along the direction


void InputPlayer::MoveForward(float dt)
{
	glm::vec3 temp(0, 0, 5);
	temp = glm::rotateZ(temp, player->GetAngleZ());
	player->SetPos(player->GetPos() + temp * dt);
}

But, what I'm getting is the ship moving along the Z axes (LH coordinate system btw) without caring about the direction.

What I'm doing wrong? I'm going nuts... T_T

Thanks in advance for help.

Simply put you are rotating about the wrong axis. Your temp vec points down the z-axis and then you rotate it about the z-axis, all that does is to roll the vector which doesn't really do anything, it still points down the z-axis. Have you tried debugging this and steping through? You will probably see that temp is still (0, 0, 5) after doing rotateZ.

What is it you expect to happen? Are you trying to yaw or pitch? If you want to yaw then you need to rotate about the y-axis (I assume up is y?), for pitch you want to rotate about the x axis. This assumes up/down is y, left/right is x and forward/back is z.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Advertisement

Since the game is supposed to be in space, the spaceship may be pointing upward and slightly on the left and thus thrust forward in that direction. So yeah, I need to do both yaw and pitch. Am I right?

Since the game is supposed to be in space, the spaceship may be pointing upward and slightly on the left and thus thrust forward in that direction. So yeah, I need to do both yaw and pitch. Am I right?

Yeah you have the right idea, just in the example you posted you are choosing the wrong axis to rotate about. Eventually you probably will want to also rotate about the z-axis (roll). Since your game is a space game I would suggest you stop using euler angles as soon as possibly, they are a terrible choice when you want full 3d movement and it will cause you no end of misery! For example if your ship were to pitch up 90 degrees and then decide to yaw 90 degrees it will probably roll instead. You might notice that kinda behaviour happening a lot in fps games but it's not really a problem there.

Instead you should try to use quaternions to represent your ship's orientation. I briefly Googled to check and glm does support quaternions. I came across this tutorial that is doing rotations using glm quaternions, it might be of some use to you:
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/

Your ship would instead of having angles would have a quaternion orientation. Then in your move forward you would do something like:

void InputPlayer::MoveForward(float dt)
{
glm::vec3 temp(0, 0, 5);
temp = player->GetOrientation() * temp; // Where GetOrientation() returns a quaternion
player->SetPos(player->GetPos() + temp * dt);
}

I'm not familiar with glm so I can't say that will compile right off but that is the general idea.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Thanks! That was very helpful. :) I'm gonna give a shot to quaternions asap. :) Thanks again!

I would generally recommend against using quaternions unless you can explain in great detail why they are superior to matrices. There are cases where quaternions are the answer, but pitch, yaw, and roll (which are not Euler angles by the way) not being functional is not one of them.

If you are using Unity, Unity favors quaternions and so it might be worthwhile pursuing them. But you're using GLM. So, master matrices before worrying about quaternions.

Using a facing(angle) vector is probably not what you wanted. You probably want several vectors.

For a spaceship simulator, I would have a velocity vector that represents the movement of the ship per frame. The length of the vector would be the distance it moves per frame and the direction of the vector would be the direction it moves until being told to change heading. I would start this out as a zero vector so that there is initially no movement.

I would create an acceleration vector that represents the engine thrust. This vector would point in the direction of the engine opposite the direction of thrust. It's length would be the distance change per second each frame. So, when the engine is turned on, I would add the acceleration vector to the velocity vector each frame while the engine is on. This would alter the velocity vector to change the speed and possibly the direction.

The velocity vector gets applied to (added to) the position (which technically is not a vector but a point in space stored in a vector so we can do vector math on it) every frame regardless. The acceleration vector basically steers the velocity vector. Applying, the acceleration vector in the opposite direction of the velocity vector will slow the ship down and eventually stop it and reverse course.

A ship with full physics like this is actually a bit difficult to control/pilot. I've been intending to make a 3D spaceship simulator with the full physics simulation like this for awhile. I did a simple one as an example in 2D using XNA. I wrote it as a tutorial that you might want to read if you really want to get into this. Understanding 2D ship control is a little easier than 3D and so it's a good place to start. The tutorial is mostly about how engines placed on different points of the ship affect it in addition to what I was just talking about here. That was the intro page, here is the actual tutorial page since the intro page may not make the link clear.

For a more simple simulation, you can forget about the acceleration vector and just rotate and change the length of your velocity vector directly. I think your problem may have been that you are not rotating the velocity vector to change the ship direction. If you do the full physics simulation with acceleration vectors, you would only rotate the velocity vector when torque occurs which goes back to the tutorial I pointed out.

I would recommend that you watch my videos on Vectors, Matrices, and Gimbal Lock in that order on my YouTube channel at VirtuallyProgramming.com. The first two will make you much more familiar with the math involved here for GLM. The Gimbal Lock video will show you why you should not be storing orientation information as pitch, yaw, and roll values. I recommend using matrices for storing the position and orientation of the ship. For the purpose of Gimbal Lock, quaternions have no advantage here and have the disadvantages of not being what the graphics card needs because it will eventually have to be turned into a world matrix anyway, and not having the ability to store position and requiring that to be separate information from the orientation (which is not a huge problem but matrices can).

I'm not totally against quaternions. I believe SLERP is one very valid reason to favor quaternions for skinned animation. I just don't know that they are the go-to tool for everything. And your graphics card (vertex shader) is going to want to be fed matrices, which is a huge argument in their favor.

It's a little more tricky, but I would generally store my ship's position and orientation in it's world/model matrix. Then I would pull that information out when needed. For example, you can get a forward vector pretty easily from it's world matrix. One of the columns in the matrix is it's Z axis direction. This should be a normalized vector which only gives you the direction of the ship. So, your velocity vector could be built by taking that normalized vector and multiplying it times the ship's current velocity (making the velocity a float instead of a vec3 until you multiply the vec3 times the forward vector). The ship's position is the 4th column (or is it row because I always get row major and column major mixed up when working with matrices) vector. It's a vec4 like everything else in the 4 by 4 matrix. You can throw away the 4th value. The first 3 are the x, y, and z values of the position. You can turn that into a vec3 for the ship's position.

To actually move the ship, I would create the velocity and position vectors, then add them together to get the new position, then apply a translation matrix to change the position of the object's world matrix by multiplying them together and giving me a new matrix with the new position for each frame.

If you do the full physics simulation, the ship can be moving in an entirely different direction than the engines are pushing. In space it's pretty easy to move sideways. On earth aerodynamics and drag cause problems with lateral movement. But in space, it's normal.

So, to change heading you actually have two issues. One is to change the direction of the velocity vector which is your actual direction of travel. And the other is to change the direction of the ship's nose/bow so you can look where you are going which requires a rotation (torque) to align with the direction of travel.

It can all get a little complicated, so you may want to do a simplified version of just the velocity vector and manipulate it directly rather than using an acceleration vector. But acceleration vectors are actual real world physics.

Check out those tutorials. I think they will be worth your time albeit probably several hours of material to go through.

And to answer your question more directly: I would check "GetAngleZ". I would also step through the code with a debugger to make sure the values are what you expect them to be. Temp is your forward vector you could get from the ship's world matrix. Although the way you are building it it assumes a velocity of 5 per frame and a direction aligned with the Z axis. Your rotation should change that heading. I don't see anything wrong there at a glance other than rotating around the z axis is a roll and you probably want a Y axis rotation for yaw as pointed out earlier.

Advertisement

I would generally recommend against using quaternions unless you can explain in great detail why they are superior to matrices. There are cases where quaternions are the answer, but pitch, yaw, and roll (which are not Euler angles by the way) not being functional is not one of them.


Quaternions are more compact, much easier to renormalize and better for interpolating. Is that enough detail for you?

Regardless of how you are representing rotations internally, you should have a mechanism to apply a rotation to a vector, without worrying about the details. So your code should look something like this:
void InputPlayer::MoveForward(float dt) {
  player->SetPos(player->GetPos() + apply_rotation(player->GetAttitude(), glm::vec3(0, 0, 5)));
}

This topic is closed to new replies.

Advertisement