How-to give a player dynamic agility
by Joobot · 08/22/2005 (12:20 am) · 8 comments
First off, open your player.h. after the lines:
Point3F mLastPos; ///< Holds the last position for physics updates
Point3F mLastWaterPos; ///< Same as mLastPos, but for water
add:
S32 agility;
S32 runForce;
S32 maxForwardSpeed;
S32 maxBackwardSpeed;
S32 maxSideSpeed;
S32 maxUnderwaterForwardSpeed;
S32 maxUnderwaterBackwardSpeed;
S32 maxUnderwaterSideSpeed;
S32 jumpForce;
Why: This places your agility settings unde the player namespace, not the PlayerData namespace,w hich is shared by ALL players, but ours is diffrent for each player.
After the lines:
void onCameraScopeQuery(NetConnection *cr, CameraScopeQuery *);
void writePacketData(GameConnection *conn, BitStream *stream);
void readPacketData (GameConnection *conn, BitStream *stream);
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
Add:
void setAgility(S32 value);
Why: Thisis is the definition of a function that not only sets your agility, but also updates your speed and forces accordingly.
Open player.cc and after:
mBubbleEmitterTime = 10.0;
mLastWaterPos.set( 0.0, 0.0, 0.0 );
mMountPending = 0;
Add:
agility = 10;
runForce = 4320;
maxForwardSpeed = 14;
maxBackwardSpeed = 13;
maxSideSpeed = 13;
maxUnderwaterForwardSpeed = 8.4;
maxUnderwaterBackwardSpeed = 7.8;
maxUnderwaterSideSpeed = 7.8;
jumpForce = 747;
Why: This gives your agility fields something to be at the startup.
After:
U32 retMask = Parent::packUpdate(con, mask, stream);
Add:
if (stream->writeFlag(mask & CharMask))
stream->writeInt(agility,5);
Why: This sends the agility field to the client to hekp the serevr and the client remain in sync.
After:
Parent::unpackUpdate(con,stream);
Add:
if (stream->readFlag())
{
S32 agility = stream->readInt(5);
setAgility(agility);
}
Why this is where the lient recieves the agility variable and updfates the other fields with the setAgility function that has not yet been made.
After:
}
F32 energy = stream->readFloat(EnergyLevelBits) * mDataBlock->maxEnergy;
setEnergyLevel(energy);
}
Add:
static void cSetAgility(SimObject *ptr, S32, const char **argv)
{
Player* obj = static_cast(ptr);
obj->setAgility(dAtof(argv[2]));
}
void Player::setAgility(S32 value)
{
if(value > 0)
agility = value;
else
agility = 1;
runForce = 4320.0 * (agility / 10.0);
maxForwardSpeed = 14.0 * (agility / 10.0);
maxBackwardSpeed = 13.0 * (agility / 10.0);
maxSideSpeed = 13.0 * (agility / 10.0);
maxUnderwaterForwardSpeed = 8.4 * (agility / 10.0);
maxUnderwaterBackwardSpeed = 7.8 * (agility / 10.0);
maxUnderwaterSideSpeed = 7.8 * (agility / 10.0);
jumpForce = 747.0 * (agility / 10.0);
if(isServerObject())
setMaskBits(CharMask);
}
Why: These two functions both set the agility and update the agility related fields. the first one is a console method that can be used in the torque console.
After:
Con::addVariable("Player::minWarpTicks",TypeF32,&sMinWarpTicks);
Con::addVariable("Player::maxWarpTicks",TypeS32,&sMaxWarpTicks);
Con::addVariable("Player::maxPredictionTicks",TypeS32,&sMaxPredictionTicks);
Add:
Con::addCommand("Player", "setAgility", cSetAgility, "obj.setAgility(value)", 3, 8);
Why: This links our console method into the Torque console.
REPLACE!!!:
// Clamp water movement
if (move->y > 0)
{
if( mWaterCoverage >= 0.9 )
moveSpeed = getMax(mDataBlock->maxUnderwaterForwardSpeed * move->y,
mDataBlock->maxUnderwaterSideSpeed * mFabs(move->x));
else
moveSpeed = getMax(mDataBlock->maxForwardSpeed * move->y,
mDataBlock->maxSideSpeed * mFabs(move->x));
}
else
{
if( mWaterCoverage >= 0.9 )
moveSpeed = getMax(mDataBlock->maxUnderwaterBackwardSpeed * mFabs(move->y),
mDataBlock->maxUnderwaterSideSpeed * mFabs(move->x));
else
moveSpeed = getMax(mDataBlock->maxBackwardSpeed * mFabs(move->y),
mDataBlock->maxSideSpeed * mFabs(move->x));
}
With:
// Clamp water movement
if (move->y > 0)
{
if( mWaterCoverage >= 0.9 )
moveSpeed = getMax(maxUnderwaterForwardSpeed * move->y,
maxUnderwaterSideSpeed * mFabs(move->x));
else
moveSpeed = getMax(maxForwardSpeed * move->y,
maxSideSpeed * mFabs(move->x));
}
else
{
if( mWaterCoverage >= 0.9 )
moveSpeed = getMax(maxUnderwaterBackwardSpeed * mFabs(move->y),
maxUnderwaterSideSpeed * mFabs(move->x));
else
moveSpeed = getMax(maxBackwardSpeed * mFabs(move->y),
maxSideSpeed * mFabs(move->x));
}
Why: This makes it so movement is controlled by the fields in Player not PlayerData.
Replace:
F32 maxAcc = (mDataBlock->runForce / mMass) * TickSec;
With:
F32 maxAcc = (runForce / mMass) * TickSec;
Why: Same as last reason.
Replace:
F32 impulse = mDataBlock->jumpForce / mMass;
With:
F32 impulse = jumpForce / mMass;
Why: Same reason again.
And there you go. To use it, get a player's handle and int the torque console type.setAgility()
Point3F mLastPos; ///< Holds the last position for physics updates
Point3F mLastWaterPos; ///< Same as mLastPos, but for water
add:
S32 agility;
S32 runForce;
S32 maxForwardSpeed;
S32 maxBackwardSpeed;
S32 maxSideSpeed;
S32 maxUnderwaterForwardSpeed;
S32 maxUnderwaterBackwardSpeed;
S32 maxUnderwaterSideSpeed;
S32 jumpForce;
Why: This places your agility settings unde the player namespace, not the PlayerData namespace,w hich is shared by ALL players, but ours is diffrent for each player.
After the lines:
void onCameraScopeQuery(NetConnection *cr, CameraScopeQuery *);
void writePacketData(GameConnection *conn, BitStream *stream);
void readPacketData (GameConnection *conn, BitStream *stream);
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
Add:
void setAgility(S32 value);
Why: Thisis is the definition of a function that not only sets your agility, but also updates your speed and forces accordingly.
Open player.cc and after:
mBubbleEmitterTime = 10.0;
mLastWaterPos.set( 0.0, 0.0, 0.0 );
mMountPending = 0;
Add:
agility = 10;
runForce = 4320;
maxForwardSpeed = 14;
maxBackwardSpeed = 13;
maxSideSpeed = 13;
maxUnderwaterForwardSpeed = 8.4;
maxUnderwaterBackwardSpeed = 7.8;
maxUnderwaterSideSpeed = 7.8;
jumpForce = 747;
Why: This gives your agility fields something to be at the startup.
After:
U32 retMask = Parent::packUpdate(con, mask, stream);
Add:
if (stream->writeFlag(mask & CharMask))
stream->writeInt(agility,5);
Why: This sends the agility field to the client to hekp the serevr and the client remain in sync.
After:
Parent::unpackUpdate(con,stream);
Add:
if (stream->readFlag())
{
S32 agility = stream->readInt(5);
setAgility(agility);
}
Why this is where the lient recieves the agility variable and updfates the other fields with the setAgility function that has not yet been made.
After:
}
F32 energy = stream->readFloat(EnergyLevelBits) * mDataBlock->maxEnergy;
setEnergyLevel(energy);
}
Add:
static void cSetAgility(SimObject *ptr, S32, const char **argv)
{
Player* obj = static_cast
obj->setAgility(dAtof(argv[2]));
}
void Player::setAgility(S32 value)
{
if(value > 0)
agility = value;
else
agility = 1;
runForce = 4320.0 * (agility / 10.0);
maxForwardSpeed = 14.0 * (agility / 10.0);
maxBackwardSpeed = 13.0 * (agility / 10.0);
maxSideSpeed = 13.0 * (agility / 10.0);
maxUnderwaterForwardSpeed = 8.4 * (agility / 10.0);
maxUnderwaterBackwardSpeed = 7.8 * (agility / 10.0);
maxUnderwaterSideSpeed = 7.8 * (agility / 10.0);
jumpForce = 747.0 * (agility / 10.0);
if(isServerObject())
setMaskBits(CharMask);
}
Why: These two functions both set the agility and update the agility related fields. the first one is a console method that can be used in the torque console.
After:
Con::addVariable("Player::minWarpTicks",TypeF32,&sMinWarpTicks);
Con::addVariable("Player::maxWarpTicks",TypeS32,&sMaxWarpTicks);
Con::addVariable("Player::maxPredictionTicks",TypeS32,&sMaxPredictionTicks);
Add:
Con::addCommand("Player", "setAgility", cSetAgility, "obj.setAgility(value)", 3, 8);
Why: This links our console method into the Torque console.
REPLACE!!!:
// Clamp water movement
if (move->y > 0)
{
if( mWaterCoverage >= 0.9 )
moveSpeed = getMax(mDataBlock->maxUnderwaterForwardSpeed * move->y,
mDataBlock->maxUnderwaterSideSpeed * mFabs(move->x));
else
moveSpeed = getMax(mDataBlock->maxForwardSpeed * move->y,
mDataBlock->maxSideSpeed * mFabs(move->x));
}
else
{
if( mWaterCoverage >= 0.9 )
moveSpeed = getMax(mDataBlock->maxUnderwaterBackwardSpeed * mFabs(move->y),
mDataBlock->maxUnderwaterSideSpeed * mFabs(move->x));
else
moveSpeed = getMax(mDataBlock->maxBackwardSpeed * mFabs(move->y),
mDataBlock->maxSideSpeed * mFabs(move->x));
}
With:
// Clamp water movement
if (move->y > 0)
{
if( mWaterCoverage >= 0.9 )
moveSpeed = getMax(maxUnderwaterForwardSpeed * move->y,
maxUnderwaterSideSpeed * mFabs(move->x));
else
moveSpeed = getMax(maxForwardSpeed * move->y,
maxSideSpeed * mFabs(move->x));
}
else
{
if( mWaterCoverage >= 0.9 )
moveSpeed = getMax(maxUnderwaterBackwardSpeed * mFabs(move->y),
maxUnderwaterSideSpeed * mFabs(move->x));
else
moveSpeed = getMax(maxBackwardSpeed * mFabs(move->y),
maxSideSpeed * mFabs(move->x));
}
Why: This makes it so movement is controlled by the fields in Player not PlayerData.
Replace:
F32 maxAcc = (mDataBlock->runForce / mMass) * TickSec;
With:
F32 maxAcc = (runForce / mMass) * TickSec;
Why: Same as last reason.
Replace:
F32 impulse = mDataBlock->jumpForce / mMass;
With:
F32 impulse = jumpForce / mMass;
Why: Same reason again.
And there you go. To use it, get a player's handle and int the torque console type
About the author
#2
" deprecated in favor of ConsoleMethod?
I don't even recall seeing anymore "c" functions in the Torque codebase anymore, as they are now ConsoleMethods or ConsoleFunctions... Of course, I very well could be wrong...
Robert
08/22/2005 (1:51 pm)
Wasn't "cI don't even recall seeing anymore "c
Robert
#3
08/30/2005 (1:17 am)
Con::addCommand is also deprecated
#4
Con::addCommand("Player", "setAgility", cSetAgility, "obj.setAgility(value)", 3, 8);
and
static void cSetAgility(SimObject *ptr, S32, const char **argv) { ... }
use this:
ConsoleMethod( Player, setAgility,void,3,3,"(S32 value)")
{
object->setAgility(dAtoi(argv[2]));
}
09/01/2005 (8:35 pm)
Instead of using this:Con::addCommand("Player", "setAgility", cSetAgility, "obj.setAgility(value)", 3, 8);
and
static void cSetAgility(SimObject *ptr, S32, const char **argv) { ... }
use this:
ConsoleMethod( Player, setAgility,void,3,3,"(S32 value)")
{
object->setAgility(dAtoi(argv[2]));
}
#5
What is CharMask supposed to be? Is it a variable you left out of the resource accidentally, because it doesn't exist in mine. I'm working from 1.3.
EDIT:
Ok, I found where CharMask needs to be thanks to this resource http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=2698 , which this one appears to be based on. You have to add the CharMask enum to the Maskbits in the Player.
10/04/2005 (9:59 am)
if (stream->writeFlag(mask & CharMask))What is CharMask supposed to be? Is it a variable you left out of the resource accidentally, because it doesn't exist in mine. I'm working from 1.3.
EDIT:
Ok, I found where CharMask needs to be thanks to this resource http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=2698 , which this one appears to be based on. You have to add the CharMask enum to the Maskbits in the Player.
#6
10/06/2005 (1:51 pm)
Has anyone that's implemented this had their player start spazzing out when they use an agility of 5 or less? You see it when you drop the camera at the player or die, basically when the player is not the control object. Could PlayerData and Player be clashing somewhere?
#7
02/09/2006 (11:31 am)
I implemented this resource and then had my aiplayers start falling through the terrain when they received move commands. If that happens to you, this simple fix worked for me. In aiplayer.cc change:AIPlayer::AIPlayer()to
AIPlayer::AIPlayer() : Player()Hope that helps :D
#8
03/11/2008 (11:16 pm)
Does anyone know why my bots run at normal speed on diagonals when using this modification? It's odd, I give them an agility of 4 and they run slow on the straight sections, then speed back up on the diagonals. It's very odd :P 
Torque Owner Dreamer
Default Studio Name
[ code ] Code goes here [ / code ]
Make sure to remove the spaces between the brackets first though. :)