But that’s not what I’m talking about.
The issue
In your normal FPS game, you use WSAD to move your player about, right. But when you turn your camera in a different direction WSAD still work, but W is still forward, its not on any axis its forward.
Take this chunk of code:
const float SPD=1.0f; // move the player if (KeyDown(‘A’)) mPlayer.mPos.x-=SPD; if (KeyDown(‘D’)) mPlayer.mPos.x+=SPD; if (KeyDown(‘W’)) mPlayer.mPos.z+=SPD; if (KeyDown(‘S’)) mPlayer.mPos.z-=SPD
Yes its move the player about using WSAD, but how do we add in the turning?
const float RSPD=D2R(60); // 60 degrees per second // turn the player if (KeyDown(VK_LEFT)) mPlayer.mTurn.x-=RSPD; // yaw if (KeyDown(VK_RIGHT)) mPlayer.mTurn.x+=RSPD; // yaw
This will turn the model, but when we press WSAD the player will still move in the same directions as before, it will not take into account the rotation that we have applied.
Using Maths
Now: some of you may remember your basic sine & cosine trigonometry.
And with a little work, you could change this into the proper formula needed for figuring out the correct movement direction.
However I have a quicker simpler solution: using the DirectX matrix code.
Using DirectX Maths
Consider this code:
// DO NOT COPY THIS CODE: it does not work const float RSPD=D2R(60); // 60 degrees per second // turn the player if (KeyDown(VK_LEFT)) mPlayer.mTurn.x-=RSPD; // yaw if (KeyDown(VK_RIGHT)) mPlayer.mTurn.x+=RSPD; // yaw // get the rotation matrix MATRIX rot=CreateRotationMatrix(mPlayer.mTurn); // move the player if (KeyDown(‘A’)) mPlayer.mPos+=LEFT*rot; // move left if (KeyDown(‘D’)) mPlayer.mPos+=RIGHT*rot; // move right if (KeyDown(‘W’)) mPlayer.mPos+=FORWARD*rot; // move forward if (KeyDown(‘S’)) mPlayer.mPos+=BACK*rot; // move back
What we are doing here is rotating the player like normal. Then when we move the player, instead of moving in the X, Y or Z direction, we take the movement vector & rotate it based upon the players rotation matrix. That way the W is forward, no matter which way the player is facing.
The actual DirectX code is a little more complex than this, but not by much (you just need to know what the funtions are):
// This is valid code const float RSPD=D2R(60); // 60 degrees per second // turn the player (as usual) // .... // create a rotation matrix using the players turn D3DXMATRIX rot; D3DXMatrixRotationYawPitchRoll(&rot,mPlayer.mTurn.x,mPlayer.mTurn.y,mPlayer.mTurn.z); D3DXVECTOR3 dir(0,0,0); // the direction to move // update dir if (KeyDown('A')) dir.x--; // move left if (KeyDown('D')) dir.x++; // move right if (KeyDown('W')) dir.z++; // move forward if (KeyDown('S')) dir.z--; // move back // now lets rotate 'dir' by the rotation matrix 'rot' D3DXVECTOR3 rdir; // rotated direction D3DXVec3TransformCoord(&rdir,&dir,&rot); // rdir=dir*rot // finally add it to the players position mPlayer.mPos+=rdir*SPD;
To simplify the coding a little, I captured all the key presses and updated the vector ‘dir’ before performing the final multiplication.
The main piece of code to note is the D3DXVec3TransformCoord which is used to multiply the matrix and vector together.
Using this idea elsewhere
Using this idea elsewhere:
Lets consider firing some shots:
if (player presses fire) { CShot* ptr=new CShot(); // Create the CShot ptr->mVel=D3DXVECTOR3(-1,0,0);// set the velocity // etc,etc,etc }
This code assumes the shot is going one way only.
But we can use the same concept to rotate the shots.
if (player presses fire) { CShot* ptr=new CShot(); // Create the CShot D3DXVECTOR3 vel(0,0,-1); // get the rotation matrix D3DXMATRIX rot; D3DXMatrixRotationYawPitchRoll(&rot,mPlayer.mTurn.x,mPlayer.mTurn.y,mPlayer.mTurn.z); // rotate it D3DXVECTOR3 rvel; D3DXVec3TransformCoord(&rvel,&vel,&rot); // rdir=dir*rot; ptr->mVel=rdir; // set the velocity // etc,etc,etc }
You can also use the same idea if you wanted the shot to be fired from a certain part of the model: measure the offset of the firing point, rotate by the matrix, fire shot from the players location + rotated offset.
Another good use is the third person camera. Here are the rough steps:
Pick the offset for the camera, say 5 units up, 20 units behind the player
Multiply this offset by the players rotation matrix
Set camera location=players location + rotated offset
Make the camera look directly at the player
Conclusion:
Its funny how a little bit of maths can make your game so much more interesting. When I first learned trigonometry, I learned it because I had to.
Once I started writing games, I found that all sorts of bits of math that I learned were actually really handy. In particular was trigonometry.
Happy coding
Mark
No comments:
Post a Comment