Game Development Community

Making a Player Fly

by Mark Pumphrey · in Torque Game Engine · 07/15/2005 (3:31 am) · 125 replies

Firstly I would like to state that "Yeah, I have seen the posts about flying but....". They don't work and/or full of bugs. I would like to also state a general request that if you make a post regarding code to edit the original post instead continually trying to 'add' corrections later on making it harder than hell to read. Also, EVERYONE has a copy and paste function of some kind, use it. Saying that "here is some code than will change your life, insert it anywhere" means nothing and helps even less. Ok, enough of that. Has anyone actually made a player fly just like in Tribes?

About the author

Recent Threads

#41
05/14/2006 (4:50 pm)
It's often the innovative use of several techniques that warrants a resource. It's up to you though... no pressure ;-)
#42
05/15/2006 (2:24 am)
Sadly I do not have much time and all parts are not finished yet but this is a fast idea of how we do it, a thing worth noting is that we are not using our resources on the computer so effectivley that you would maybe want to do in a comersial game but it is a fast trick that is easy to do if you are doing a school project like me and is always short on time.

1. Make a invisible model, this is something the 3D graphic people handles
* make a "PNG" texture that has full alpha.
* mounting stuff
* !The dummy will handle the collision so make sure to get it right here!

2. Make another, animated model... in our case a insect that we will use int the game as our vehicle ;)

3. in the game, declare a flyingvehicle datablock and set shape = dumm model.

4. declare a StaticShape datablock for the animated model.

5. at player creation (in "game.cs") first create the flyingvehicle as your controlled character and then imidiatley mount the animated character on it, the trick is to get the animated character to mount so that the dummy ends up in the middle of the model.

Play and enjoy, a fast animated flying vehicle!

Bonus, the visible model is mounted so you could hot swap the model in the game easily and make easy transformations... kind of kirby style to change your characters apperance =)
#43
05/15/2006 (4:35 am)
Nice one. all the information required :)
#44
06/26/2006 (9:10 pm)
I thread has been very useful but I have a question about it. How could you change it where when you move forward to plays the run animation then if you stop it goes back to the root?
#45
01/03/2007 (8:50 pm)
Has this been turned in to a resource yet?
#46
01/04/2007 (6:29 am)
I tell ya what, when I come to make the other games I want to make that require flying, I'll try to make a resource out of it. The game I'm working on now doesn't require flying - quite the opposite, I'm trying to figure out how to make Torque NOT fly and bounce around so much
#47
01/05/2007 (5:09 pm)
I've implemented this code in the "starter.fps" template and it works well. However, TGE crashes when the player collides with the computer-controlled orc. Anyone experience the same thing or have any ideas where I should start to look for the the source of the problem?
#48
01/05/2007 (9:12 pm)
I figured out what I did wrong: I used Tom Spilman's fix to smooth flight, but I missed his note about adding lines in Player::readPacketData(). For fellow code box scanners out there, you need to add the following lines to player.cc (add the lines denoted with plus signs):

void Player::readPacketData(GameConnection *connection, BitStream *stream)
{

...

   stream->read(&mHead.x);
   stream->read(&mHead.z);
   stream->read(&rot.z);
+  stream->read(&rot.x);
+  stream->read(&rot.y);
   rot.x = rot.y = 0;
   setPosition(pos,rot);
#49
02/06/2007 (5:00 pm)
For some reason this is causing my rigidshapes (boulders) to go sky rocketing in the air at the load of the map.
#50
09/16/2007 (1:07 pm)
I think I have an idea that could help the "Toggle" function. Make 2 packages, 1 with the walking code, and one with the flying one, then bind a button to activate the package, that's the easiest way I found to do.
#51
11/08/2007 (7:44 pm)
Any news on this resource? Air/Ground toggle? Got the flying to work perfect, But i also need ground aswell :P
#52
12/04/2007 (4:08 pm)
I think they were talking about mFlying booleans know anything?
#53
12/05/2007 (1:48 pm)
Anyone know what the code is for the mFlying boolean?
#54
12/06/2007 (7:42 am)
I don't have the time to write the code for it right now but I probably will in the next couple days.

edit: almost done but I need to study for my math finals :P probably will be able to finish it today or tomorrow assuming nothing goes wrong.
#55
12/06/2007 (3:46 pm)
So I put it all together. I haven't tested this much, but I do know that flight tends to be a bit jittery. I'm not sure if it was always this way, if not I'll check it out. I didn't go to far to understand everything so I when you go out of flying mode it may stop doing something that the flying needs. Here goes.

find

// Acceleration due to gravity
   VectorF acc(0,0,mGravity * mGravityMod * TickSec);

change it to

VectorF acc;//we have to create acc out here and then declare it inside the statements or else the compiler
		       //won't think that it exists
   if(mFlying){
	  acc = VectorF(0.0f, 0.0f, 0.0f);
   }else{
	  acc = VectorF(0.0f, 0.0f, mGravity * mGravityMod * TickSec);
   }

Next scroll down just a little and find

// Acceleration on run surface
   if (runSurface) {
      mContactTimer = 0;

change it to

// Acceleration on run surface
   if (runSurface||mFlying) {
	   if(mFlying)
		  mContactTimer = 30;
	   else
		  mContactTimer = 0;

Then scroll down a bit more and find

if (pvl) {
         VectorF nn;
         mCross(pv,VectorF(0,0,1),&nn);
         nn *= 1 / pvl;
         VectorF cv = contactNormal;
         cv -= nn * mDot(nn,cv);
         pv -= cv * mDot(pv,cv);
         pvl = pv.len();
      }

change it to

if (pvl&&!mFlying) {
         VectorF nn;
         mCross(pv,VectorF(0.0f, 0.0f, 1.0f),&nn);
         nn *= 1.0f / pvl;
         VectorF cv = contactNormal;
         cv -= nn * mDot(nn,cv);
         pv -= cv * mDot(pv,cv);
         pvl = pv.len();
      }
#56
12/06/2007 (3:51 pm)
I've been following Matt's initial progression for a bit here. All I have had to do thus far is add an if statement or modify and existing one. It gets a bit tougher, but I tried to make it as nice as possible. For those of you who looked at the code you may have wondered where mFlying came from, I will provide the code that defines that later. Anyways time for the big code block.

Scroll all the way back up to the top of Player::updateMove() and find

// Update current orientation
   if (mDamageState == Enabled) {
      F32 prevZRot = mRot.z;
      delta.headVec = mHead;

      F32 p = move->pitch;
      if (p > M_PI) p -= M_2PI;
      mHead.x = mClampF(mHead.x + p,mDataBlock->minLookAngle,
                        mDataBlock->maxLookAngle);

      F32 y = move->yaw;
      if (y > M_PI) y -= M_2PI;

      GameConnection* con = getControllingClient();
      if (move->freeLook && ((isMounted() && getMountNode() == 0) ||
          (con && !con->isFirstPerson())))
      {
         mHead.z = mClampF(mHead.z + y,
                           -mDataBlock->maxFreelookAngle,
                           mDataBlock->maxFreelookAngle);
      }
      else
      {
         mRot.z += y;
         // Rotate the head back to the front, center horizontal
         // as well if we're controlling another object.
         mHead.z *= 0.5;
         if (mControlObject)
            mHead.x *= 0.5;
      }

      // constrain the range of mRot.z
      while (mRot.z < 0)
         mRot.z += M_2PI;
      while (mRot.z > M_2PI)
         mRot.z -= M_2PI;

      delta.rot = mRot;
      delta.rotVec.x = delta.rotVec.y = 0;
      delta.rotVec.z = prevZRot - mRot.z;
      if (delta.rotVec.z > M_PI)
         delta.rotVec.z -= M_2PI;
      else if (delta.rotVec.z < -M_PI)
         delta.rotVec.z += M_2PI;

      delta.head = mHead;
      delta.headVec -= mHead;
   }
   MatrixF zRot;
   zRot.set(EulerF(0, 0, mRot.z));

   // Desired move direction & speed
   VectorF moveVec;
   F32 moveSpeed;
   if (mState == MoveState && mDamageState == Enabled)
   {
      zRot.getColumn(0,&moveVec);
      moveVec *= move->x;
      VectorF tv;
      zRot.getColumn(1,&tv);
      moveVec += tv * move->y;

      // Clamp water movement

- continued in next post -
#57
12/06/2007 (3:54 pm)
- continue -

Now replace that code block with

// Update current orientation
   if (mDamageState == Enabled) {
      Point3F prevRot = mRot;
      delta.headVec = mHead;

      F32 p = move->pitch;
      if (p > M_PI_F)
         p -= M_2PI_F;
      mHead.x = mClampF(mHead.x + p,mDataBlock->minLookAngle,
                        mDataBlock->maxLookAngle);

      F32 y = move->yaw;
      if (y > M_PI_F)
         y -= M_2PI_F;

      GameConnection* con = getControllingClient();
      if (move->freeLook && ((isMounted() && getMountNode() == 0) || (con && !con->isFirstPerson())))
      {
         mHead.z = mClampF(mHead.z + y,
                           -mDataBlock->maxFreelookAngle,
                           mDataBlock->maxFreelookAngle);
      }
      else
      {
         mRot.x += p;
         mRot.z += y;
         // Rotate the head back to the front, center horizontal
         // as well if we're controlling another object.
         mHead.z *= 0.5f;
         if (mControlObject)
            mHead.x *= 0.5f;
      }

      // constrain the range of mRot.z
      while (mRot.z < 0.0f)
         mRot.z += M_2PI_F;
      while (mRot.z > M_2PI_F)
         mRot.z -= M_2PI_F;

      // constrain the range of mRot.x
	  if(mRot.x > 1.5706)
		 mRot.x = 1.5706;
	  else if(mRot.x < -1.5706)
		 mRot.x = -1.5706

      delta.rot = mRot;
      delta.rotVec = prevRot - mRot;
      if (delta.rotVec.z > M_PI_F)
         delta.rotVec.z -= M_2PI_F;
      else if (delta.rotVec.z < -M_PI_F)
         delta.rotVec.z += M_2PI_F;

      delta.head = mHead;
      delta.headVec -= mHead;
   }
   MatrixF zRot;
   zRot.set(EulerF(0.0f, 0.0f, mRot.z));
   if(mFlying){
	   MatrixF xRot;
	   xRot.set(EulerF(mRot.x, 0, 0));
	   zRot.mul(zRot, xRot); //well its not zrot anymore but the code is a bit more efficient this way
   }


   // Desired move direction & speed
   VectorF moveVec;
   F32 moveSpeed;
   if (mState == MoveState && mDamageState == Enabled)
   {
      zRot.getColumn(0,&moveVec); //note that if you are flying its not zRot it is xzRot
      moveVec *= move->x;
      VectorF tv;
      zRot.getColumn(1,&tv);
      moveVec += tv * move->y;
	  if(mFlying){
		  zRot.getColumn(2,&tv);
		  moveVec += tv * move->z;
	  }

      // Clamp water movement

well if I made any mistakes that is probably where they are. It does work though and I was surprised with how clean the code worked out to be.
#58
12/06/2007 (4:12 pm)
(I'm just going to copy what Matt said here because it works)
Now if you are like me and think that the falling animation looks better for flying around then jump over to Player::pickActionAnimation() and scroll down till you find:

if (mContactTimer >= sContactTickTime) {
         // Nothing under our feet
         action = PlayerData::RootAnim;
      }

change it to

if (mContactTimer >= sContactTickTime) {
         // Nothing under our feet
		  if(mFlying)
			  action = PlayerData::FallAnim;
		  else
			  action = PlayerData::RootAnim;
      }

Well that's where Matt left off but I get to keep going, hopefully I remember it all.

So lets go back up near the top to 'Player::Player()' under

mState = MoveState;
   mFalling = false;

put

mFlying  = false;

find

ConsoleMethod( Player, getState, const char*, 2, 2, "Return the current state name.")
{
   return object->getStateName();
}

above it put

void Player::setFlying(bool Flying){
	mFlying = Flying;
}
bool Player::getFlying(){
	return mFlying;
}
//----------------------------------------------------------------------------
ConsoleMethod( Player, toggleFlying, bool, 2, 3, "(bool Flying)")
{
   bool Flying = (argc > 2)? dAtob(argv[2]): !object->getFlying();
   object->setFlying(Flying);
   return 1;
}

I'm not sure if that's the "right" place but it works as well as any.

Now we are moving on over to player.h

under

ActionState mState;              ///< What is the player doing? @see ActionState
   bool mFalling;                   ///< Falling in mid-air?

put

bool mFlying;					///< Should we take off towards the sun?

a little bit under that find

static void consoleInit();

under it add

void setFlying(bool Flying);
   bool getFlying();

Well I think that's all done. I didn't add Tom Spilman's change in this list but you should probably scroll up and add it, and make sure to add the onread packet stuff as well.
#59
12/08/2007 (4:04 pm)
Ok I got that code in, but what is the command to toggle it? I tried:

toggleFlying;
mFlying = true;
setFlying
mFlying
setFlying = true;

none of those worked.
#60
12/09/2007 (8:22 am)
I just tried 2 more:

mFlying = Flying
Player, toggleFlying, bool, 2, 3, "(bool Flying)"

Still none works.