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

#81
12/09/2007 (5:44 pm)
Ok I just changed it... compiling

EDIT: Still shaking.
#82
12/09/2007 (6:08 pm)
I am trying to work on the default.bind.cs thing since it doesn't seem to be working. I tried:
GlobalActionMap.bind(keyboard, "t", toggleFlying);
and I also did your way, still nothing.
#83
12/09/2007 (6:19 pm)
Do you get any errors in the console when you press 't' my way, it is looking for the function you put in commands.cs if it can't find it then it will make errors.
#84
12/10/2007 (1:01 pm)
Well I can't find any errors.

EDIT: One second, lemme try this...
#85
12/10/2007 (1:20 pm)
Ok it's flying. But I don't know why it's still shaking.
#86
12/10/2007 (1:29 pm)
If your wondering how I fixed it, I just copied the commands.cs from starter.fps to tutorial.base and got rid of the command suicide (I won't be needing it).
#87
12/10/2007 (3:42 pm)
I'll see if I can work out the shaking, it might be a bit though. I have my math finals in two days so I'm going into crunch time.
#88
12/10/2007 (4:03 pm)
I found out how to make it work barely...

In readPacketData, find:

stream->read(&mHead.x);
   stream->read(&mHead.z);
   stream->read(&rot.x);
   stream->read(&rot.y);
   stream->read(&rot.z);
The code that Tom said, add this line:

stream->read(&mHead.x);
   stream->read(&mHead.z);
   stream->read(&rot.x);
   stream->read(&rot.y);
   stream->read(&rot.z);
   [b]stream->read(&mFlying);[/b]
Do the same for writePacketData and the shaking will stop.

EDIT: Well it seems this works when you don't collide with anything, the same problem Tom had. I do not know why because I put the code in he said would fix it, for some reason it didn't.
#89
12/12/2007 (5:42 pm)
Ok, does anyone else know what to do?
#90
12/14/2007 (2:25 pm)
How can I bind the toggle fly command to a GUI button?
#91
12/15/2007 (2:15 pm)
Anyone?
#92
12/15/2007 (5:01 pm)
You may have to research this, try here...but I have a solution below

Issues with using Mouse to activate gui's and keep as input for game...
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=13034
www.garagegames.com/mg/forums/result.thread.php?qt=34289

How gui's work...
tdn.garagegames.com/wiki/GUI/Getting_Started

Here's specific GUI TGE 1.5 stuff...
tdn.garagegames.com/wiki/GUI/Tips1_5

The gui you probably want use...
GuiButtonCtrl

The solution

Binding a function to a GUI to control a variable

Out of the goodness of my heart - and coz I wanted to know too here's a working example...

Add

Find your PlayGui.gui in client/ui and add this at the bottom (if possible)
NOTE: $gFlying should be cut out of this code and put in another script, probably the script that controls flying so it can be changed here in PlayGui.ui but is accessed in the code that needs it.
I've put a tooltip in there as well.

Troubleshoot

You may need to toggle cursorOn() and cursorOff() depending on how you use the mouse (see above) - to test just bring up the console and type cursorOn() if you can't see your cursor at runtime.

How it works

The main way it works is by adding the command=""; member to the class. This can call your own function when you press the button (not sure if it has to stay in PlayGui.ui). Make sure you include the semi colon in the quotes and outside.
command = "toggleFlying();";

Expansion

I guess if you wanted to you could call a function in a class somewhere else - say in your beasty's class. So if you have a class called Beasty() that had a function/method called toggleFlying() you could change your guibuttonctrl to be
command = "Beasty::toggleFlying();";
...but I haven't tested that so try it once you get the code below to work.

The code

new GuiButtonCtrl() {
      canSaveDynamicFields = "0";
      Profile = "GuiButtonProfile";
      HorizSizing = "right";
      VertSizing = "bottom";
      position = "150 425";
      Extent = "140 30";
      MinExtent = "8 2";
      canSave = "1";
      Visible = "1";
      command = "toggleFlying();";
      tooltipprofile = "GuiDefaultProfile";
      ToolTip = "Press this button to toggle flying";
      hovertime = "1000";
      text = "Toggle Flying";
      groupNum = "-1";
      buttonType = "PushButton";
   };
};
//--- OBJECT WRITE END ---

$gFlying = false; // put this in your game code somewhere else, will make this global

function toggleFlying()
{
   if ($gFlying == true) 
       $gFlying = false;
   else
      $gFlying = true;
      
}
#93
12/15/2007 (9:08 pm)
Thanks, I already knew how to make a GUI button, I just got stumped on how to put the function in (I gotta continue reading that book...). Well my main problem is the shaking, if you look a little above, you will see what I've tried. I can't seem to find anything wrong though.
#94
12/15/2007 (9:51 pm)
Quote:Found my last jitter glitch. If you add a mFlying boolean to toggle flying like i did, you need to update both the pack/unpackUpdate and the write/readPacketData. write/readPacketData is sent regularly from the server to your controller client. pack/unpackUpdate is used for the initial update of all clients and used for remote clients that are ghosted to the local client. If you don't send your mFlying boolean in both you'll get rapid toggles of flying and falling.
He says we need to update them... Update them with what?
#95
12/16/2007 (4:18 pm)
Update the "write/readPacketData" means to do this...make sure your code looks like this

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

if (stream->readFlag()) {
      // Only written if we are not mounted
      stream->read(&pos.x);
      stream->read(&pos.y);
      stream->read(&pos.z);
      stream->read(&mVelocity.x);
      stream->read(&mVelocity.y);
      stream->read(&mVelocity.z);
      stream->setCompressionPoint(pos);
      delta.pos = pos;
      mJumpSurfaceLastContact = stream->readInt(4);
   }
   else
      pos = delta.pos;
   stream->read(&mHead.x);
   stream->read(&mHead.z);
   stream->read(&rot.x);
   stream->read(&rot.y);
   stream->read(&rot.z);
   stream->read(&mFlying);

then in void Player::writePacketData(GameConnection *connection, BitStream *stream)...

if (stream->writeFlag(!isMounted())) {
      // Will get position from mount
      stream->setCompressionPoint(pos);
      stream->write(pos.x);
      stream->write(pos.y);
      stream->write(pos.z);
      stream->write(mVelocity.x);
      stream->write(mVelocity.y);
      stream->write(mVelocity.z);
      stream->writeInt(mJumpSurfaceLastContact > 15 ? 15 : mJumpSurfaceLastContact, 4);
   }
   stream->write(mHead.x);
   stream->write(mHead.z);
   stream->write(mRot.x);
   stream->write(mRot.y);
   stream->write(mRot.z);
   stream->write(mFlying);

for the pack/unpackUpdate change to this...

in void Player::unpackUpdate(NetConnection *con, BitStream *stream)...

if(stream->readFlag())
      {
         stream->readNormalVector(&mVelocity, 10);
         mVelocity *= stream->readInt(13) / 32.0f;
      }
      else
      {
         mVelocity.set(0.0f, 0.0f, 0.0f);
      }
      
      //rot.y = rot.x = 0.0f;
      rot.x = stream->readFloat(7) * M_2PI_F;
      rot.y = stream->readFloat(7) * M_2PI_F;
      rot.z = stream->readFloat(7) * M_2PI_F;
      
      mHead.x = stream->readSignedFloat(6) * mDataBlock->maxLookAngle;
      mHead.z = stream->readSignedFloat(6) * mDataBlock->maxLookAngle;

      mFlying = stream->readFlag();
      
      delta.move.unpack(stream);

then in U32 Player::packUpdate(NetConnection *con, U32 mask, BitStream *stream)...

if(stream->writeFlag(len > 0.02f))
      {
         Point3F outVel = mVelocity;
         outVel *= 1.0f/len;
         stream->writeNormalVector(outVel, 10);
         len *= 32.0f;  // 5 bits of fraction
         if(len > 8191)
            len = 8191;
         stream->writeInt((S32)len, 13);
      }
      stream->writeFloat(mRot.x / M_2PI_F, 7);
      stream->writeFloat(mRot.y / M_2PI_F, 7);
      stream->writeFloat(mRot.z / M_2PI_F, 7);

      stream->writeSignedFloat(mHead.x / mDataBlock->maxLookAngle, 6);
      stream->writeSignedFloat(mHead.z / mDataBlock->maxLookAngle, 6);

      stream->writeFlag(mFlying); 

      delta.move.pack(stream);

NOTE! You must write and read data in the same order other wise the data gets swapped around

Also, I haven't tested the code above but in theory it works - the concept is to pack the data and write the data in the correct order on the server and then unpack and read the data on the client

It would cool if someone could check this for me.

@Tyler - if you still can't get it to work I will run the update myself as I have a vampire that I want to fly, and will show you how I did it.

EDIT : changed line
stream->readFlag(mFlying);
to...
stream->writeFlag(mFlying);
#96
12/16/2007 (4:43 pm)
I can't seem to get the GUI to work, I need the GUI to call a function to the server which is this:

function serverCmdtoggleFly(%client)
{
   if (isObject(%client.player))
      %client.player.toggleFlying();
}

It seems to work when I bind it to a button using a GlobalActionCommand:

GlobalActionMap.bindCmd(keyboard, "t", "commandToServer(\'toggleFly\');", "");
As you can tell, with the codes up there, whenever you press t, you will start flying. I still can't find any way to have the serverCmdtoggleFly function to activate when I press it.
#97
12/16/2007 (4:50 pm)
Where is your serverCmdtoggleFly?

The function you call in PlayGui has to be in PlayGui at the bottom and then get it to call serverCmdtoggleFly

like in PlayGui.gui...

new GuiButtonCtrl() {
...
   command = "toggleFlying();";
...
...
}

function toggleFlying()
{
    serverCmdtoggleFly();
}
#98
12/17/2007 (12:56 pm)
I just tried to put the above player.cc code in and got the following errors:

*None*

I will try and fix as many as possible.

EDIT: Just fixed a simple error (needed a semicolon). I will take the 2 off...

EDIT: I found out that you accidently said:

stream->readFlag(mFlying);

Which should be:

stream->[b]write[/b]Flag(mFlying);

Well that takes care of all the errors...
#99
12/17/2007 (1:20 pm)
It still doesn't seem to work, whenever I toggle the flying off, then back on, it vibrates. Although I did find out that if I press f7, it resets and then when I turn flying back on, it isn't vibrating. I think I may be able to do the rest in script if I do something like:

function serverCmdtoggleFlying(%client)
{
    %client.player.setTransform(LocalClientConnection.player.getTransform());
    if (isObject(%client.player))
       %client.player.toggleFlying();
}

I hope this works...
#100
12/17/2007 (1:29 pm)
Houston! We have lift-off! It works!