Game Development Community

dev|Pro Game Development Curriculum

Sprint Button

by Daniel Neilsen · 05/13/2002 (10:56 am) · 79 comments

Download Code File

Adding a Player Sprint Key


by Daniel "Wizard_TPG" Neilsen
wizardsworld@bigpond.com


This is quite a simple thing to do but requires the editing of
several files in the torque engine. I have based this on the
latest HEAD version as at 13/5/02 but, I originally coded this
for the original release of torque so it should be compatible
with all torque versions to date.

Before we go too much further I should say this
DISCLAIMER - I am certainly not the best at C++ in the world but
this worked for me so it should work for you too.
- The line numbers are taken from my edit version of
the engine so should be considered approximate only.



STEP 1 - Adding a sprint toggle into the engine

Open MoveManager.h and add this line to line 29
bool sprint;

result should look like this
bool freeLook;
bool sprint;
bool trigger[MaxTriggerKeys];


Add this to line 50
static bool mSprint;

result should look like this
static bool mFreeLook;
static bool mSprint;
static F32 mPitch;
static F32 mYaw;
static F32 mRoll;


Open GameConnectionMoves.cc and add this line to line 29
bool MoveManager::mSprint = false;

result should look like this
bool MoveManager::mFreeLook = false;
bool MoveManager::mSprint = false;
F32 MoveManager::mPitch = 0;
F32 MoveManager::mYaw = 0;
F32 MoveManager::mRoll = 0;


Add this to line 64
Con::addVariable("mvSprint", TypeBool, &mSprint);

result should look like this
Con::addVariable("mvFreeLook", TypeBool, &mFreeLook);
Con::addVariable("mvSprint", TypeBool, &mSprint);
Con::addVariable("mvPitch", TypeF32, &mPitch);
Con::addVariable("mvYaw", TypeF32, &mYaw);
Con::addVariable("mvRoll", TypeF32, &mRoll);


Add this to line 148
stream->writeFlag(sprint);

result should look like this
stream->writeFlag(freeLook);
stream->writeFlag(sprint);


Add this to line 172
sprint = stream->readFlag();

result should look like this
freeLook = stream->readFlag();
sprint = stream->readFlag();


Add this to line 199
curMove.sprint = MoveManager::mSprint;

result should look like this
curMove.freeLook = MoveManager::mFreeLook;
curMove.sprint = MoveManager::mSprint;


Open default.bind.cs and add the following
function toggleSprint( %val )
{
if ( %val )
$mvSprint = true;
else
$mvSprint = false;
}
moveMap.bind( keyboard, q, toggleSprint );


ok, cool, we got a sprint button....but it dosnt do didly squat...doh!
hmmm better make it do something then eh?

Just a quick offside... For those that didnt notice, we literally copied the freelook
all the way. This method can be used for any toggle button you wish to add.



STEP 2 - THE SPRINT DATABLOCK SETTINGS

The next step is to add new properties into the playerdata datablock
for the sprint speed, force, energy drain and min energy


Open player.h and add the following at line 57
F32 SprintSpeedMult; // Player max speed increase when sprinting eg. 1.2 = 20% increase
F32 SprintForceMult; // Player run force increase when sprinting eg. 1.2 = 20% increase
F32 sprintEnergyDrain; // Energy drain/tick
F32 minSprintEnergy; // Energy required to sprint

Result should look like this:
F32 SprintSpeedMult;
F32 SprintForceMult;
F32 sprintEnergyDrain; // Energy drain/tick
F32 minSprintEnergy;
F32 maxStepHeight;
F32 runSurfaceAngle; // Angle from vertical in degrees



Open player.cc and add the following at line 170
SprintSpeedMult = 1.2;
SprintForceMult = 1.2;
sprintEnergyDrain = 2;
minSprintEnergy = 2;

Result should look like this:
SprintSpeedMult = 1.2;
SprintForceMult = 1.2;
sprintEnergyDrain = 2;
minSprintEnergy = 2;
maxStepHeight = 1;
runSurfaceAngle = 80;



add the following at line 450
addField("SprintSpeedMult", TypeF32, Offset(SprintSpeedMult, PlayerData));
addField("SprintForceMult", TypeF32, Offset(SprintForceMult, PlayerData));
addField("sprintEnergyDrain", TypeF32, Offset(sprintEnergyDrain, PlayerData));
addField("minSprintEnergy", TypeF32, Offset(minSprintEnergy, PlayerData));

Result should look like this:
addField("SprintSpeedMult", TypeF32, Offset(SprintSpeedMult, PlayerData));
addField("SprintForceMult", TypeF32, Offset(SprintForceMult, PlayerData));
addField("sprintEnergyDrain", TypeF32, Offset(sprintEnergyDrain, PlayerData));
addField("minSprintEnergy", TypeF32, Offset(minSprintEnergy, PlayerData));
addField("runSurfaceAngle", TypeF32, Offset(runSurfaceAngle, PlayerData));
addField("recoverDelay", TypeS32, Offset(recoverDelay, PlayerData));
addField("recoverRunForceScale", TypeF32, Offset(recoverRunForceScale, PlayerData));



add the following at line 643
stream->write(SprintSpeedMult);
stream->write(SprintForceMult);
stream->write(sprintEnergyDrain);
stream->write(minSprintEnergy);

Result should look like this:
stream->write(SprintSpeedMult);
stream->write(SprintForceMult);
stream->write(sprintEnergyDrain);
stream->write(minSprintEnergy);
stream->write(recoverDelay);
stream->write(recoverRunForceScale);



add the following at line 761
stream->read(&SprintSpeedMult);
stream->read(&SprintForceMult);
stream->read(&sprintEnergyDrain);
stream->read(&minSprintEnergy);

Result should look like this:
stream->read(&runSurfaceAngle);
stream->read(&SprintSpeedMult);
stream->read(&SprintForceMult);
stream->read(&sprintEnergyDrain);
stream->read(&minSprintEnergy);
stream->read(&recoverDelay);
stream->read(&recoverRunForceScale);




STEP 3 - THE MOVEMENT

Now we have the button working, and we have the sprint settings in the engine
Time to make it all work. The basics of sprinting is we are "amplifying" the
players speed.


Before these three lines at approx line 1660

// Desired move direction & speed
VectorF moveVec;
F32 moveSpeed;

add the following:

//Check if sprinting
F32 tempSprintSpeedMult;
F32 tempSprintForceMult;
tempSprintSpeedMult = 1;
tempSprintForceMult = 1;

if (move->sprint)
{
tempSprintSpeedMult = mDataBlock->SprintSpeedMult;
tempSprintForceMult = mDataBlock->SprintForceMult;
if (mEnergy < mDataBlock->minSprintEnergy)
{
tempSprintSpeedMult = 1;
tempSprintForceMult = 1;
}
}



Change the following lines at approx line 1422 like so..

if (move->y > 0)
{
if( mWaterCoverage >= 0.9 )
moveSpeed = getMax(mDataBlock->maxUnderwaterForwardSpeed * tempSprintSpeedMult * move->y,
mDataBlock->maxUnderwaterSideSpeed * tempSprintSpeedMult * mFabs(move->x));
else
moveSpeed = getMax(mDataBlock->maxForwardSpeed * tempSprintSpeedMult * move->y,
mDataBlock->maxSideSpeed * tempSprintSpeedMult * mFabs(move->x));
}
else
{
if( mWaterCoverage >= 0.9 )
moveSpeed = getMax(mDataBlock->maxUnderwaterBackwardSpeed * tempSprintSpeedMult * mFabs(move->y),
mDataBlock->maxUnderwaterSideSpeed * tempSprintSpeedMult * mFabs(move->x));
else
moveSpeed = getMax(mDataBlock->maxBackwardSpeed * tempSprintSpeedMult * mFabs(move->y),
mDataBlock->maxSideSpeed * tempSprintSpeedMult * mFabs(move->x));
}




Change the following lines at approx line 1482 like so..

VectorF pv;
if(moveSpeed > 0)
{
if (move->sprint && mEnergy >= mDataBlock->minSprintEnergy)
{
mEnergy -= mDataBlock->sprintEnergyDrain;
}
else if (mEnergy >= mDataBlock->minRunEnergy)
{
mEnergy -= mDataBlock->runEnergyDrain;
pv = moveVec;
}
}
else
pv.set(0,0,0);



Change the following lines at approx line 1513 like so..

// Clamp acceleratin, player also accelerates faster when
// in his hard landing recover state.
F32 maxAcc = (mDataBlock->runForce / mMass) * TickSec;
if (move->sprint)
maxAcc *= mDataBlock->SprintForceMult;
if (mState == RecoverState)
maxAcc *= mDataBlock->recoverRunForceScale;
if (runSpeed > maxAcc)
runAcc *= maxAcc / runSpeed;
acc += runAcc;


And there you have it. A working sprint key.

Enjoy :)
Page«First 1 2 3 4 Next»
#61
04/10/2006 (3:36 pm)
How can you fix it where the player can't sprint sides and backwards, they can only sprint forward?
#62
05/25/2006 (6:00 am)
Works fine. Great work!

@Tek0
I think you can do that by adding variables and changing the appropriate loop - I might take a look at it, but it seems simple enough to me.
#63
11/14/2006 (9:03 pm)
Did this for 1.5. When I press 'q' to sprint the player sprints but only in one direction and I cant control the player.


FIXED

I changed this code a little to get the player to stop sprinting when the energy runs out, and be able to control direction.


// Force a 0 move if there is no energy, and only drain
      // move energy if we're moving.
		VectorF pv;
		if( moveSpeed > 0 )
		{
			if ( (move->sprint) && (mEnergy >= mDataBlock->minSprintEnergy) )
			{
				mEnergy -= mDataBlock->sprintEnergyDrain;
				pv = moveVec;
			}
			else
			{
				pv.set(0,0,0);
			}

			if (mEnergy >= mDataBlock->minRunEnergy) 
			{
				mEnergy -= mDataBlock->runEnergyDrain;
				pv = moveVec;
			}

		}
		else
		{
			pv.set(0,0,0);
		}



Here's my settings for player.cs:
rechargeRate = 0.1;

   SprintSpeedMult = 2;
   SprintForceMult = 2;
   sprintEnergyDrain = 0.3;
   minSprintEnergy = 5;

   runForce = 48 * 90;
   runEnergyDrain = 0;
   minRunEnergy = 0;
   maxForwardSpeed = 6;
   maxBackwardSpeed = 4;
   maxSideSpeed = 5;
#64
06/20/2007 (11:42 am)
Here's a way to just increase speed in script (without affecting energy) -- works as a cheat for zipping around a map, just remember to comment out the keybind before distribution :)

www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=13082
#65
08/12/2007 (4:43 am)
Awesome bit of code got working with 1.5.2 this week 11 august 2007

I tried just scripting to avoid recompiling using infinitum3d's link, but i couldnt figure out how to do energy drain properly. Not sure its a great idea to script communication between client-server for energy drain, probably much better to use similar to health drain.

Attached it to "lshift" so that lshift sprints
i have an example game compiled from my build
available at www.darksprite.co.uk
look for most current version

here is what i put in default.binds.cs
was trying to put a message on the screen everytime it was pressed
although it looks like a toggle it acts like a press / depress button

// 11 August 2007 sprint function

function toggleSprint( %val )
{
if ( %val )
{
$mvSprint = true;
// %message = "sprinting";
// %time = 2;
// %lines = 1;
// centerPrint(%message, %time, %lines );
}
else
{
$mvSprint = false;
// %message = "not sprinting";
// %time = 2;
// %lines = 1;
// centerPrint(%message, %time, %lines );
}
}
moveMap.bind( keyboard, "lshift", toggleSprint );
#66
11/30/2007 (1:08 pm)
this sprint thing have to much code here and there...fixed here and there and so on.... kan some one that have made this work write a summery... write the hole code again with all the fixes :P

spring key
energy bar
stop spring after emergy bar is empty...

thx for helping, and thats Daniel for the great thred!
#67
10/10/2008 (6:23 am)
@Christopher - You're right. A "script-only" sprint with energy drain would apparently require too many client/server calls, and therefore too much network traffic. I finally went back and added this to my 1.5.2 but it's not working for me. I've got it bound to "alt w", but it gets ignored in-game. I can still walk and strafe, but "alt w" does nothing.

I did a "rebuild" without errors, and deleted all .dso's (and my config.cs)...

Should the SprintSpeedMult = 1.2f (what is that, float?) Would that make any difference?

Gotta go back and recheck everything.

EDIT: triple checked everything, even reloaded my backup file and tried again. Built my solution, deleted .dso's and config...

Still not working TGE1.5.2. Others said they got it working though, so must be an error on MY part. I don't suppose anyone would like to post their working version of player.cc here :)

I'm sure I just have something in the wrong spot.

Tony
#68
10/15/2008 (5:33 pm)
Works in TGE 1.5.2 and in TGEa 1.7.1. Line # guides are crap but every position is easily found for copy/pasters. Only the one missing line mentioned above (Sabrecyd (Jun 05, 2002 at 08:00)) needs to be added to the instructions.

When adding to TGEa note that GameConnectionMoves.cc is now called moveManager.cpp

The effect is subtle however because you are already running (+20% to 14 m/s is only 16.8 m/s), and it drains your energy very quickly so you don't sprint for long at all. Remember that the default settings are just a guideline and will need to changed. But they can be moved/copied into the PlayerData datablock (player.cs) for easier tweaking.
#69
12/22/2008 (8:31 am)
Nice resource - works beautifully for me. Just a question. In NullMove, it seems to be initialising all the move's parameters. If we add a flag, this parameter isn't being initialised, is it? So I added another 'false,' after the first 'false,' of that initialisation, and it broke jumping, firing, and sprinting. Why does initialising a parameter break the move construct? Or am I misunderstanding how the initialisation works?
#70
06/03/2009 (8:56 am)
Cool resource, thank you.

A little addition - if you want the run (side, back) animation to speed up when you sprint, find the following in player.cpp:

mShapeInstance->setTimeScale(mActionAnimation.thread,
                                   mActionAnimation.forward? scale: -scale);

and just before that add:

// check if we're sprinting
		if (Con::getBoolVariable("$mvSprint")) {
			scale = scale * mDataBlock->sprintSpeedMult;
		}

Your player will now not only move faster, it will also run faster. Tested in Torque3D only, though it should work everywhere.
#71
06/03/2009 (3:31 pm)
Thanks as always Konrad!!!
#72
06/03/2009 (4:35 pm)
Sometimes these little things can bring so much to the table, never would have thought of that myself -- Thanks Konrad!
#73
06/03/2009 (6:24 pm)
You're welcome Ari & Michael, but I just thought about this.. that $mvSprint is client side only, thankfully, so won't work in a multiplayer game, only single player. The thing will never get executed on the server, because there's no such variable.
Not hard to fix for multiplayer though:

player.h add member variable to the Player class
bool mSprint;

player.cpp at the top of updateMove after delta.move = *move:
mSprint = move->sprint;

and finally right before
mShapeInstance->setTimeScale(mActionAnimation.thread,  
                                   mActionAnimation.forward? scale: -scale);

add
// check if we're sprinting  
        if (mSprint) {  
            scale = scale * mDataBlock->sprintSpeedMult;  
        }

Since move->sprint is already networked, mSprint should always have the right value on the server. I didn't test in multiplayer, but it should work.
#74
10/05/2009 (11:34 am)
@Konrad, your animation speed code makes the root animation speed up if the sprint key is down but you are not moving. to fix this change the
// check if we're sprinting  
         if (Con::getBoolVariable("$mvSprint")) {  
           scale = scale * mDataBlock->sprintSpeedMult;  
         }
to
// check if we're sprinting  
	  if (Con::getBoolVariable("$mvSprint") && ((Con::getFloatVariable("$mvForwardAction") !=0) || (Con::getFloatVariable("$mvBackwardAction") != 0) || 
		  (Con::getFloatVariable("$mvLeftAction") != 0) || (Con::getFloatVariable("$mvRightAction") != 0))) {  
             scale = scale * mDataBlock->sprintSpeedMult;
         }

This was only tested in T3D 1.0
#75
10/05/2009 (12:00 pm)
I wonder why I didn't think of that! :)

Thanks for the fix, Bryce!
#76
11/06/2009 (4:46 am)
Anyone know or figure out how to make it not regen while you have the button pressed, energy bar jitters quite a bit while running which i'd like to smoothe out a bit by having energy not regen while the button is pressed.

seems like it'd happen in
// Energy management
   if (mDamageState == Enabled && mDataBlock->inheritEnergyFromMount == false) {
      F32 store = mEnergy;
      mEnergy += mRechargeRate;
      if (mEnergy > mDataBlock->maxEnergy)
         mEnergy = mDataBlock->maxEnergy;
      else
         if (mEnergy < 0)
            mEnergy = 0;

      // Virtual setEnergyLevel is used here by some derived classes to
      // decide whether they really want to set the energy mask bit.
      if (mEnergy != store)
         setEnergyLevel(mEnergy);
   }

like that above code needs to be nested in an if like.
if (curmove.sprint)
do nothing
else
then the above code

just not sure how to actually do it.
#77
12/05/2009 (12:16 am)
I am close to implementing this resource, but I am running into a problem. I can get the code to recompile without errors and have bound sprint to q. However, whenever I press the q button, nothing happens. There are no error messages in the console, including when I press q.

I wonder if this has to do with these two lines, which are referenced in the resource but which don't appear in the TGEA 1.7.1 version of movemanager.cpp.

curMove.freeLook = MoveManager::mFreeLook;
curMove.sprint = MoveManager::mSprint;

Could anyone help me figure out where to put these two lines?
More generally, does anyone have any suggestions on how to get the sprinting to work.

Any help would be greatly appreciated.
#78
12/05/2009 (12:26 am)
I don't know how related this would be, but I was having trouble with saved config.cs. That should update your keybinds. Still I don't know how relevant that is with TGEA.
#79
04/02/2011 (4:19 pm)
curMove.freeLook = MoveManager::mFreeLook;

That line is in moveList.cpp in TGEA 182 in case anybody tries this resource.

It should end up looking like:

curMove.freeLook = MoveManager::mFreeLook;
curMove.sprint = MoveManager::mSprint;//***SPRINT***

Page«First 1 2 3 4 Next»