The Flight Compendium
by Bruno Grieco · 01/30/2005 (1:07 am) · 85 comments
The Flight Compendium
This is an attempt to gather the most important resources I found regarding flight and flying bots I found hanging around GG site. So please keep in mind that I'm just putting together information that other people created. Also, I'm a programmer and my skills in math and physics aren't really great so I don't really understand much of the calculations that are being done, but I do understand where they start and end so I was able to encapsulate them properly.
Acknowledgements
I would like to thank Badguy for his vehicle steering code, Wendell Brown that had actually achieved the bot 3D flight on this thread, F.W. Hardijzer for his excellent Air Control resource, Erik Madison for the Swimming Resource that pointed the way in how to control simple flight and everyone else I forgot to mention that contributed to the heavier-than-air flight.
Simple vs. Complex Flight
There are two ways of flying. The simple way which is making a Player (and an AIPlayer for inheritance) take of the ground and walk in mid-air and the complex way that involves mounting an AIPlayer onto a vehicle and have it fly around. The main difference about them are the physics involved.
You should choose the simple flight method if : your player is supposed to fly on his own, for instance if he has wings (note that there is a Jet Pack resource that will handle if your player has such item), if you need precision in the spot you send your AIPlayer to (since complex flight involves inertia, the move tolerance is bigger), and you are adverse to C++ coding ( even though you will have to do some )
Meanwhile, the complex flight is for those who require a more realistic flight movement, need vehicles to fly and aren't afraid of a compiler.
Simple Flight
The main problem about flying is that you need a Z coordinate (height) to send your bot to, unfortunately the move algorithm only deals with XY plane coordinates, the Z is ignored, it's only used to check if you are falling or climbing something (a hill) in both cases it will check the datablock to see what should be done (fall, or reduce the speed).
The solution to this problem came from the swimming resource, it uses the SetAimLocation() function to determine the direction to tilt the player and the height it should achive.
Coding :
You should edit the Player.cc file ( in engine/Game ) and replace the Player::updateMove() function for this one (It looks big but copy&Paste will do the trick):
Complex Flight
Complex Flight will be implemented directly on AIPlayer. This will enable a bot to pilot flying, wheeled and hover vehicles. The Z-coord info is passed to the aim location on the SetMoveDestination function ( which would also work in Simple Flight ).
In order to maintain the original Move capability, the getAIMove function should be renamed to getAIOnFootMove and a new getAIMove and a getAIMountedMove will be provided.
Coding :
In AIPlayer.h, insert :
In AIPlayer.c substitute :
( remember to rename the previous getAIMove to getAIOnFootMove )
and insert :
in FlyingVehicle.cc, around line 36
Usage
In order to the bot to pilot it, you must create the bot and the vehicle. Then you mount the bot in the vehicle using the function below :
the bot should now drive the vehicle correctly when using %bot.setMoveDestination().
Datablocks
Before complaining that the resource doesn't work, and your plane or hoverthing doesn't go wherever you want to, keep in mind that the great villain in this matter can and will be your Datablock. They can be pretty nasty and even FREEZE the game so I'm adding below the datablocks for wheeled, flying and hover vehicles that did work for me.
But there is only one way of having the vehicles behaving the way you want : TWEAKING.
Vehicle physics are yet a great mystery to me and I have very little or even no idea of how those little parameters work out together.
Wheled Vehicle Datablock
Flying Vehicle Datablock
Hover Vehicle Datablock
Disclaimer
OK guys, that's about it. That's all I know about vehicles, hope it helps.
This is an attempt to gather the most important resources I found regarding flight and flying bots I found hanging around GG site. So please keep in mind that I'm just putting together information that other people created. Also, I'm a programmer and my skills in math and physics aren't really great so I don't really understand much of the calculations that are being done, but I do understand where they start and end so I was able to encapsulate them properly.
Acknowledgements
I would like to thank Badguy for his vehicle steering code, Wendell Brown that had actually achieved the bot 3D flight on this thread, F.W. Hardijzer for his excellent Air Control resource, Erik Madison for the Swimming Resource that pointed the way in how to control simple flight and everyone else I forgot to mention that contributed to the heavier-than-air flight.
Simple vs. Complex Flight
There are two ways of flying. The simple way which is making a Player (and an AIPlayer for inheritance) take of the ground and walk in mid-air and the complex way that involves mounting an AIPlayer onto a vehicle and have it fly around. The main difference about them are the physics involved.
You should choose the simple flight method if : your player is supposed to fly on his own, for instance if he has wings (note that there is a Jet Pack resource that will handle if your player has such item), if you need precision in the spot you send your AIPlayer to (since complex flight involves inertia, the move tolerance is bigger), and you are adverse to C++ coding ( even though you will have to do some )
Meanwhile, the complex flight is for those who require a more realistic flight movement, need vehicles to fly and aren't afraid of a compiler.
Simple Flight
The main problem about flying is that you need a Z coordinate (height) to send your bot to, unfortunately the move algorithm only deals with XY plane coordinates, the Z is ignored, it's only used to check if you are falling or climbing something (a hill) in both cases it will check the datablock to see what should be done (fall, or reduce the speed).
The solution to this problem came from the swimming resource, it uses the SetAimLocation() function to determine the direction to tilt the player and the height it should achive.
Coding :
You should edit the Player.cc file ( in engine/Game ) and replace the Player::updateMove() function for this one (It looks big but copy&Paste will do the trick):
//----------------------------------------------------------------------------
void Player::updateMove(const Move* move)
{
delta.move = *move;
// Trigger images
if (mDamageState == Enabled) {
setImageTriggerState(0,move->trigger[0]);
setImageTriggerState(1,move->trigger[1]);
}
// 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
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));
}
// Cancel any script driven animations if we are going to move.
/*if (moveVec.x + moveVec.y + moveVec.z != 0 &&
(mActionAnimation.action >= PlayerData::NumTableActionAnims
|| mActionAnimation.action == PlayerData::LandAnim))
mActionAnimation.action = PlayerData::NullAnimation;
*/
}
else
{
moveVec.set(0,0,0);
moveSpeed = 0;
}
// Acceleration due to gravity
VectorF acc(0,0,mGravity * mGravityMod * TickSec);
//VectorF acc(0,0,0.5);
// Determin ground contact normal. Only look for contacts if
// we can move.
VectorF contactNormal, normalZ(moveVec.x,-moveVec.z,moveVec.y);
bool jumpSurface = false, runSurface = false;
if (!isMounted())
findContact(&runSurface,&jumpSurface,&contactNormal);
if (jumpSurface)
mJumpSurfaceNormal = contactNormal;
// Point3F headRotation = getHeadRotation();
// acc.z = (-headRotation.x) * (mDataBlock->runForce / mMass) * TickSec;
// Acceleration on run surface
if (runSurface)
{
//Con::printf("Estou em uma Run Surface");
mContactTimer = 0;
// Remove acc into contact surface (should only be gravity)
// Clear out floating point acc errors, this will allow
// the player to "rest" on the ground.
F32 vd = -mDot(acc,contactNormal);
if (vd > 0) {
VectorF dv = contactNormal * (vd + 0.002);
acc += dv;
if (acc.len() < 0.0001)
acc.set(0,0,0);
}
// Force a 0 move if there is no energy, and only drain
// move energy if we're moving.
VectorF pv;
if (mEnergy >= mDataBlock->minRunEnergy) {
if (moveSpeed)
mEnergy -= mDataBlock->runEnergyDrain;
pv = moveVec;
}
else
pv.set(0,0,0);
// Adjust the players's requested dir. to be parallel
// to the contact surface.
F32 pvl = pv.len();
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();
}
// Convert to acceleration
if (pvl)
pv *= moveSpeed / pvl;
VectorF runAcc = pv - (mVelocity + acc);
F32 runSpeed = runAcc.len();
// Clamp acceleratin, player also accelerates faster when
// in his hard landing recover state.
F32 maxAcc = (mDataBlock->runForce / mMass) * TickSec;
if (mState == RecoverState)
maxAcc *= mDataBlock->recoverRunForceScale;
if (runSpeed > maxAcc)
runAcc *= maxAcc / runSpeed;
acc += runAcc;
// If we are running on the ground, then we're not jumping
if (mDataBlock->isJumpAction(mActionAnimation.action))
mActionAnimation.action = PlayerData::NullAnimation;
}
else
{
F32 airControl = 1.5;
mContactTimer=0;
//--- by DJMystic ---
VectorF pv;
pv = moveVec;
F32 pvl = pv.len();
if (pvl)
pv *= moveSpeed / pvl;
VectorF runAcc = pv - ( mVelocity + acc);
runAcc.z = runAcc.z * airControl;
runAcc.x = runAcc.x * airControl;
runAcc.y = runAcc.y * airControl;
F32 runSpeed = runAcc.len();
F32 maxAcc = (mDataBlock->runForce / mMass) * TickSec * airControl;
if (runSpeed > maxAcc)
runAcc *= maxAcc / runSpeed;
acc += runAcc;
//--- end by DJMystic ---
}
Point3F headRotation = getHeadRotation();
acc.z = (-headRotation.x) * (mDataBlock->runForce / mMass) * TickSec;
// Acceleration from Jumping
if (move->trigger[2] && !isMounted() && canJump())
{
// Scale the jump impulse base on maxJumpSpeed
F32 zSpeedScale = mVelocity.z;
if (zSpeedScale <= mDataBlock->maxJumpSpeed) {
zSpeedScale = (zSpeedScale <= mDataBlock->minJumpSpeed)? 1:
1 - (zSpeedScale - mDataBlock->minJumpSpeed) /
(mDataBlock->maxJumpSpeed - mDataBlock->minJumpSpeed);
// Desired jump direction
VectorF pv = moveVec;
F32 len = pv.len();
if (len > 0)
pv *= 1 / len;
// We want to scale the jump size by the player size, somewhat
// in reduced ratio so a smaller player can jump higher in
// proportion to his size, than a larger player.
F32 scaleZ = (getScale().z * 0.25) + 0.75;
// If we are facing into the surface jump up, otherwise
// jump away from surface.
F32 dot = mDot(pv,mJumpSurfaceNormal);
F32 impulse = mDataBlock->jumpForce / mMass;
if (dot <= 0)
acc.z += mJumpSurfaceNormal.z * scaleZ * impulse * zSpeedScale;
else {
acc.x += pv.x * impulse * dot;
acc.y += pv.y * impulse * dot;
acc.z += mJumpSurfaceNormal.z * scaleZ * impulse * zSpeedScale;
}
mJumpDelay = mDataBlock->jumpDelay;
mEnergy -= mDataBlock->jumpEnergyDrain;
setActionThread((mVelocity.len() < 0.5)?
PlayerData::StandJumpAnim: PlayerData::JumpAnim, true, false, true);
mJumpSurfaceLastContact = JumpSkipContactsMax;
}
}
else
{
if (jumpSurface)
{
if (mJumpDelay > 0)
mJumpDelay--;
mJumpSurfaceLastContact = 0;
}
else
mJumpSurfaceLastContact++;
}
// Add in force from physical zones...
acc += (mAppliedForce / mMass) * TickSec;
// Adjust velocity with all the move & gravity acceleration
// TG: I forgot why doesn't the TickSec multiply happen here...
mVelocity += acc;
// apply horizontal air resistance
F32 hvel = mSqrt(mVelocity.x * mVelocity.x + mVelocity.y * mVelocity.y);
if(hvel > mDataBlock->horizResistSpeed)
{
F32 speedCap = hvel;
if(speedCap > mDataBlock->horizMaxSpeed)
speedCap = mDataBlock->horizMaxSpeed;
speedCap -= mDataBlock->horizResistFactor * TickSec * (speedCap - mDataBlock->horizResistSpeed);
F32 scale = speedCap / hvel;
mVelocity.x *= scale;
mVelocity.y *= scale;
}
if(mVelocity.z > mDataBlock->upResistSpeed)
{
if(mVelocity.z > mDataBlock->upMaxSpeed)
mVelocity.z = mDataBlock->upMaxSpeed;
mVelocity.z -= mDataBlock->upResistFactor * TickSec * (mVelocity.z - mDataBlock->upResistSpeed);
}
// Container buoyancy & drag
if (mBuoyancy != 0)
{ // Applying buoyancy when standing still causing some jitters-
if (mBuoyancy > 1.0 || !runSurface) // || !mVelocity.isZero() )
mVelocity.z -= mBuoyancy * mGravity * mGravityMod * TickSec;
}
mVelocity -= mVelocity * mDrag * TickSec;
// If we are not touching anything and have sufficient -z vel,
// we are falling.
if (runSurface)
mFalling = false;
else
{
VectorF vel;
mWorldToObj.mulV(mVelocity,&vel);
mFalling = vel.z < sFallingThreshold;
}
if (!isGhost())
{
// Vehicle Dismount
if(move->trigger[2] && isMounted())
Con::executef(mDataBlock,2,"doDismount",scriptThis());
if(!inLiquid && mWaterCoverage != 0.0f)
{
Con::executef(mDataBlock,4,"onEnterLiquid",scriptThis(), Con::getFloatArg(mWaterCoverage), Con::getIntArg(mLiquidType));
inLiquid = true;
}
else if(inLiquid && mWaterCoverage == 0.0f)
{
Con::executef(mDataBlock,3,"onLeaveLiquid",scriptThis(), Con::getIntArg(mLiquidType));
inLiquid = false;
}
}
else
{
if(!inLiquid && mWaterCoverage >= 1.0f)
{
inLiquid = true;
}
else
if(inLiquid && mWaterCoverage < 0.8f)
{
if(getVelocity().len() >= mDataBlock->exitSplashSoundVel && !isMounted())
alxPlay(mDataBlock->sound[PlayerData::ExitWater], &getTransform());
inLiquid = false;
}
}
}
//----------------------------------------------------------------------------Complex Flight
Complex Flight will be implemented directly on AIPlayer. This will enable a bot to pilot flying, wheeled and hover vehicles. The Z-coord info is passed to the aim location on the SetMoveDestination function ( which would also work in Simple Flight ).
In order to maintain the original Move capability, the getAIMove function should be renamed to getAIOnFootMove and a new getAIMove and a getAIMountedMove will be provided.
Coding :
In AIPlayer.h, insert :
virtual bool getAIMountedMove(Move *move); virtual bool getAIOnFootMove(Move *move);right after the original getAIMove prototype.
In AIPlayer.c substitute :
void AIPlayer::setMoveDestination( const Point3F &location, bool slowdown )
{
mMoveDestination = location;
mMoveState = ModeMove;
mAimLocationSet = true;
mAimLocation = location;
mMoveSlowdown = slowdown;
}bool AIPlayer::getAIMove(Move *movePtr)
{
if(isMounted())
return(getAIMountedMove(movePtr));
else
return(getAIOnFootMove(movePtr));
}( remember to rename the previous getAIMove to getAIOnFootMove )
and insert :
bool AIPlayer::getAIMountedMove(Move *movePtr)
{
*movePtr = NullMove;
Point3F location;
Point3F rotation;
F32 myTol = mMoveTolerance * 7;
// now we use local space
location.x = location.y = location.z = 0.0;
rotation.x = rotation.z = 0.0;
rotation.y = 1.0;
MatrixF invTrans = getTransform();
invTrans.inverse();
// <- phdana testing
// Orient towards the aim point, aim object, or towards
// our destination.
// NOTE: you must change the protection these data members
// of AIPlayer from private to protected to get this
// to compile...
if (mAimObject || mAimLocationSet || mMoveState == ModeMove)
{
// Update the aim position if we're aiming for an object
if (mAimObject)
mAimLocation = mAimObject->getPosition();
// transform to local space
Point3F aimLocation;
invTrans.mulP(mAimLocation,&aimLocation);
F32 xDiff = aimLocation.x - location.x;
F32 yDiff = aimLocation.y - location.y;
if (!isZero(xDiff) || !isZero(yDiff)) {
// First do Yaw
// use the cur yaw between -Pi and Pi
F32 curYaw = rotation.z;
while (curYaw > M_2PI)
curYaw -= M_2PI;
while (curYaw < -M_2PI)
curYaw += M_2PI;
// find the yaw offset
F32 newYaw = mAtan( xDiff, yDiff );
F32 yawDiff = newYaw - curYaw;
// make it between 0 and 2PI
if( yawDiff < 0.0f )
yawDiff += M_2PI;
else if( yawDiff >= M_2PI )
yawDiff -= M_2PI;
// now make sure we take the short way around the circle
if( yawDiff > M_PI )
yawDiff -= M_2PI;
else if( yawDiff < -M_PI )
yawDiff += M_2PI;
movePtr->yaw = yawDiff;
// Next do pitch. This should be adjusted to run from the
// eye point to the object's center position. Though this
// works well enough for now.
F32 vertDist = aimLocation.z - location.z;
F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff);
F32 newPitch = mAtan( horzDist, vertDist ) - ( M_PI / 2.0f );
// phdana testing ->
movePtr->pitch = newPitch - rotation.x;
// <- phdan testsing
}
}
else
{
// Level out if we're not doing anything else
// Point3F headRotation = getRotation();
// movePtr->pitch = -headRotation.x;
}
// Move towards the destination
if (mMoveState == ModeMove)
{
// transform to local space
Point3F moveDestination;
invTrans.mulP(mMoveDestination,&moveDestination);
F32 xDiff = moveDestination.x - location.x;
F32 yDiff = moveDestination.y - location.y;
F32 zDiff = mMoveDestination.z - location.z;
// Check if we should mMove, or if we are 'close enough'
if ((mFabs(xDiff) < myTol) && (mFabs(yDiff) < myTol)) // && (mFabs(zDiff) < myTol ))
{
mMoveState = ModeStop;
Con::printf("AI Steering : ------------------------------------- Cheguei no destino pela função default");
throwCallback("onReachDestination");
}
else
{
// Build move direction in world space
if (isZero(xDiff))
{
movePtr->y = 1; // Always go forward
}
else
{
if (isZero(yDiff))
{
movePtr->x = (location.x > mMoveDestination.x)? -1 : 1;
}
else
{
if (mFabs(xDiff) > mFabs(yDiff))
{
F32 value = mFabs(yDiff / xDiff);
movePtr->x = (location.x > mMoveDestination.x)? -1 : 1;
movePtr->y = value;
}
else
{
F32 value = mFabs(xDiff / yDiff);
movePtr->x = (location.x > mMoveDestination.x)? -value : value;
movePtr->y = 1;
}
}
}
}
// Rotate the move into object space (this really only needs
// a 2D matrix)
Point3F newMove;
MatrixF moveMatrix;
moveMatrix.set(EulerF(0, 0, -(rotation.z + movePtr->yaw)));
moveMatrix.mulV( Point3F( movePtr->x, movePtr->y, 0 ), &newMove );
// Set movement speed. We'll slow down once we get close
// to try and stop on the spot...
if (mMoveSlowdown)
{
F32 speed = mMoveSpeed;
F32 dist = mSqrt(xDiff*xDiff + yDiff*yDiff);
F32 maxDist = 5;
if (dist < maxDist)
speed *= dist / maxDist;
movePtr->x *= speed;
movePtr->y *= speed;
}
else
{
movePtr->x *= mMoveSpeed;
movePtr->y *= mMoveSpeed;
}
// We should check to see if we are stuck...
if (location == mLastLocation)
{
throwCallback("onMoveStuck");
mMoveState = ModeStop;
}
}
// Replicate the trigger state into the move so that
// triggers can be controlled from scripts.
for( int i = 0; i < MaxTriggerKeys; i++ )
movePtr->trigger[i] = getImageTriggerState(i);
return true;
}in FlyingVehicle.cc, around line 36
sFlyingVehicleGravity = 0;
Usage
In order to the bot to pilot it, you must create the bot and the vehicle. Then you mount the bot in the vehicle using the function below :
function MountVehicle(%obj, %targetObject)
{
echo("Found a vehicle: " @ %targetObject);
onMountVehicle(%targetObject.getDataBlock(),%obj,%targetObject);
}the bot should now drive the vehicle correctly when using %bot.setMoveDestination().
Datablocks
Before complaining that the resource doesn't work, and your plane or hoverthing doesn't go wherever you want to, keep in mind that the great villain in this matter can and will be your Datablock. They can be pretty nasty and even FREEZE the game so I'm adding below the datablocks for wheeled, flying and hover vehicles that did work for me.
But there is only one way of having the vehicles behaving the way you want : TWEAKING.
Vehicle physics are yet a great mystery to me and I have very little or even no idea of how those little parameters work out together.
Wheled Vehicle Datablock
datablock WheeledVehicleData(DefaultCar)
{
category = "Vehicles";
shapeFile = "~/data/shapes/buggy/buggy.dts";
emap = true;
maxDamage = 1.0;
destroyedLevel = 0.5;
maxSteeringAngle = 0.785; // Maximum steering angle, should match animation
tireEmitter = TireEmitter; // All the tires use the same dust emitter
// 3rd person camera settings
cameraRoll = true; // Roll the camera with the vehicle
cameraMaxDist = 6; // Far distance from vehicle
cameraOffset = 1.5; // Vertical offset from camera mount point
cameraLag = 0.1; // Velocity lag of camera
cameraDecay = 0.75; // Decay per sec. rate of velocity lag
// Rigid Body
mass = 200;
massCenter = "0 -0.5 0"; // Center of mass for rigid body
massBox = "0 0 0"; // Size of box used for moment of inertia,
// if zero it defaults to object bounding box
drag = 0.6; // Drag coefficient
bodyFriction = 0.6;
bodyRestitution = 0.4;
minImpactSpeed = 5; // Impacts over this invoke the script callback
softImpactSpeed = 5; // Play SoftImpact Sound
hardImpactSpeed = 15; // Play HardImpact Sound
integration = 4; // Physics integration: TickSec/Rate
collisionTol = 0.1; // Collision distance tolerance
contactTol = 0.1; // Contact velocity tolerance
// Engine
engineTorque = 1000; // Engine power era 4000
engineBrake = 600; // Braking when throttle is 0
brakeTorque = 8000; // When brakes are applied
maxWheelSpeed = 30; // Engine scale by current speed / max speed
// Energy
maxEnergy = 100;
jetForce = 3000;
minJetEnergy = 30;
jetEnergyDrain = 2;
// Sounds
// jetSound = ScoutThrustSound;
// engineSound = BuggyEngineSound;
// squealSound = ScoutSquealSound;
// softImpactSound = SoftImpactSound;
// hardImpactSound = HardImpactSound;
// wheelImpactSound = WheelImpactSound;
// explosion = VehicleExplosion;
maxMountSpeed = 0.1;
mountDelay = 2;
dismountDelay = 1;
stationaryThreshold = 0.5;
maxDismountSpeed = 0.1;
numMountPoints = 1;
mountable = true;
mountPose[0] = "Sitting";
mountPointTransform[0] = "0 0 0 0 0 1 0";
isProtectedMountPoint[0] = false;
};Flying Vehicle Datablock
datablock FlyingVehicleData(Drone)
{
spawnOffset = "0 0 2";
emap = true;
category = "Vehicles";
shapeFile = "~/data/shapes/vehicles/Drone.dts";
multipassenger = false;
computeCRC = true;
debrisShapeName = "~/data/shapes/vehicles/Drone.dts";
debris = DroneShapeDebris;
renderWhenDestroyed = false;
mountPose[0] = sitting;
numMountPoints = 1;
isProtectedMountPoint[0] = true;
cameraMaxDist = 0.5;
cameraOffset = 4.5;
cameraLag = 0.0;
cameraRoll = true; // Roll the camera with the vehicle
// explosion = DroneVehicleExplosion;
explosionDamage = 10.5;
explosionRadius = 15.0;
maxDamage = 50.40;
destroyedLevel = 50.40;
isShielded = true;
energyPerDamagePoint = 160;
maxEnergy = 280; // Afterburner and any energy weapon pool
rechargeRate = 0.8;
integration = 4; // Physics integration: TickSec/Rate
collisionTol = 0.2; // Collision distance tolerance
contactTol = 0.1;
drag = 0.6;
density = 6.0;
minDrag = 30; // Linear Drag (eventually slows you down when not thrusting...constant drag)
rotationalDrag = 5; // Anguler Drag (dampens the drift after you stop moving the mouse...also tumble drag)
maxAutoSpeed = 10; // Autostabilizer kicks in when less than this speed. (meters/second)
autoAngularForce = 200; // Angular stabilizer force (this force levels you out when autostabilizer kicks in)
autoLinearForce = 200; // Linear stabilzer force (this slows you down when autostabilizer kicks in)
autoInputDamping = 0.95; // Dampen control input so you don't' whack out at very slow speeds
// Maneuvering
maxSteeringAngle = 0.785; // Max radiens you can rotate the wheel. Smaller number is more maneuverable.
horizontalSurfaceForce = 6; // Horizontal center "wing" (provides "bite" into the wind for climbing/diving and turning)
verticalSurfaceForce = 0.5; // Vertical center "wing" (controls side slip. lower numbers make MORE slide.)
maneuveringForce = 1400; // Horizontal jets (W,S,D,A key thrust)
steeringForce = 200; // Steering jets (force applied when you move the mouse)
steeringRollForce = 10; // Steering jets (how much you heel over when you turn)
rollForce = 20; // Auto-roll (self-correction to right you after you roll/invert)
hoverHeight = 45; // Height off the ground at rest
createHoverHeight = 45; // Height off the ground when created
maxForwardSpeed = 60; // speed in which forward thrust force is no longer applied (meters/second)
// Turbo Jet
jetForce = 3000; // Afterburner thrust (this is in addition to normal thrust)
minJetEnergy = 28; // Afterburner can't be used if below this threshhold.
jetEnergyDrain = 2.8; // Energy use of the afterburners (low number is less drain...can be fractional) // Auto stabilize speed
vertThrustMultiple = 3.0;
// Rigid body
mass = 90; //90 // Mass of the vehicle
bodyFriction = 0; // Don't mess with this.
bodyRestitution = 0.4; // When you hit the ground, how much you rebound. (between 0 and 1)
minRollSpeed = 2000; // Don't mess with this.
softImpactSpeed = 3; // Sound hooks. This is the soft hit.
hardImpactSpeed = 15; // Sound hooks. This is the hard hit.
// Ground Impact Damage (uses DamageType::Ground)
minImpactSpeed = 10; // If hit ground at speed above this then it's an impact. Meters/second
speedDamageScale = 0.06;
// Object Impact Damage (uses DamageType::Impact)
collDamageThresholdVel = 23.0;
collDamageMultiplier = 0.02;
//
minTrailSpeed = 15; // The speed your contrail shows up at.
triggerDustHeight = 4.0;
dustHeight = 1.0;
damageEmitterOffset[0] = "0.0 -3.0 0.0 ";
damageLevelTolerance[0] = 0.3;
damageLevelTolerance[1] = 0.7;
numDmgEmitterAreas = 3;
minMountDist = 2;
maxMountSpeed = 100;
checkRadius = 5.5;
observeParameters = "0 0 0";
shieldEffectScale = "0.937 1.125 0.60";
};Hover Vehicle Datablock
datablock HoverVehicleData(AssaultTank)
{
spawnOffset = "0 0 1";
floatingGravMag = 50.5;
catagory = "Vehicles";
shapeFile = "~/data/shapes/buggy/buggy.dts";
computeCRC = true;
renderWhenDestroyed = false;
drag = 0.6;
density = 0.3;
mountPose[0] = sitting;
numMountPoints = 1;
cameraMaxDist = 15.0;
cameraOffset = 5.7;
cameraLag = 5.5;
isProtectedMountPoint[0] = false;
explosionDamage = 0.5;
explosionRadius = 5.0;
lightOnly = 1;
maxDamage = 120;
destroyedLevel = 120;
isShielded = true;
rechargeRate = 0.7;
energyPerDamagePoint = 75;
maxEnergy = 150;
minJetEnergy = 15;
jetEnergyDrain = 1.3;
// Rigid Body
mass = 5;
bodyFriction = 0;
bodyRestitution = 0.5;
softImpactSpeed = 20; // Play SoftImpact Sound
hardImpactSpeed = 28; // Play HardImpact Sound
// Ground Impact Damage (uses DamageType::Ground)
minImpactSpeed = 29;
speedDamageScale = 0.010;
// Object Impact Damage (uses DamageType::Impact)
collDamageThresholdVel = 23;
collDamageMultiplier = 0.030;
dragForce = 4; // 1.9
// dragForce = 25 / 45.0;
vertFactor = 0.5;
floatingThrustFactor = 0.35;
mainThrustForce = 100;
reverseThrustForce = 70;
strafeThrustForce = 70;
turboFactor = 1.5;
brakingForce = 30;
brakingActivationSpeed = 30;
stabLenMin = 6.50;
stabLenMax = 7.25;
stabSpringConstant = 20;
stabDampingConstant = 20;
gyroDrag = 16; // 16 // 36
gyroForce = 50; //50
normalForce = 10;
restorativeForce = 100;
steeringForce = 90;
rollForce = 7;
pitchForce = 10;
minMountDist = 4;
checkRadius = 1.7785;
observeParameters = "1 10 10";
shieldEffectScale = "0.9375 1.125 0.6";
};Disclaimer
OK guys, that's about it. That's all I know about vehicles, hope it helps.
About the author
#62
Say : mAllowFlight.
Add one console method that sets it and modify the if(runSurface) to check this variable
say : if((runSurface)||(!mAllowFlight))...
This should do the trick.
07/01/2007 (4:40 pm)
What you could do is add a variable to the player class to determine if it should fly or not. Say : mAllowFlight.
Add one console method that sets it and modify the if(runSurface) to check this variable
say : if((runSurface)||(!mAllowFlight))...
This should do the trick.
#63
Im still a noob to torque when it comes to source modification. I am slowly understanding the playerData and the player class. I see where to place the "mAllowFlight" but am suspicious that it might be going to the wrong class. I thought it would go to the playerData class so that I can toggle it directly. Is this wrong?
Being such a noob still, I don't understand what you mean by "Add one console method that sets it."
Thank you again,
~Colt
07/08/2007 (11:42 pm)
Sorry I haven't replied in days. Went on a small vacation. Im still a noob to torque when it comes to source modification. I am slowly understanding the playerData and the player class. I see where to place the "mAllowFlight" but am suspicious that it might be going to the wrong class. I thought it would go to the playerData class so that I can toggle it directly. Is this wrong?
Being such a noob still, I don't understand what you mean by "Add one console method that sets it."
Thank you again,
~Colt
#64
A Console Method is the TorqueScript interface to C++. You control the player class in scripts thru them. Methods like %player.setSomething(%someValue)
Look inside the Player.cc file you'll see plenty of those defined in the bottom. Just add one new method AllowFlight() that toggles the value to 1 or 0.
07/09/2007 (12:34 pm)
The mAllowFlight should go in the Player Class.A Console Method is the TorqueScript interface to C++. You control the player class in scripts thru them. Methods like %player.setSomething(%someValue)
Look inside the Player.cc file you'll see plenty of those defined in the bottom. Just add one new method AllowFlight() that toggles the value to 1 or 0.
#65
Thank you for your help, kinda have it working. I think it works but havent been able to try it since I last compiled. I have a debug.exe to use but dont want to make a script for the toggle till I have the .exe working.
Have you ever seen anything like this?
"LINK : fatal error LNK1173: unable to find entrypoint 'DllGetObjHandler' in C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\c2.dll"
I can usually build the project fine but something amiss. Been at this problem for about an hour now and Im getting tired, thought it would help to post the problem.
I'll tell how I made the toggle in source tomorrow, for now Im out.
~Colt
BIG EDIT:
OMG.... All I have to say... I was cleaning the solution through Visual Studio and thought that would work... But no... That happened to be the reason I was getting the error lol
So I manually took the objs out (Like spring cleaning lol) and then built with the batch builder. All is well now lol Time to test that toggle. Wish me luck.
07/10/2007 (12:26 am)
@BrunoThank you for your help, kinda have it working. I think it works but havent been able to try it since I last compiled. I have a debug.exe to use but dont want to make a script for the toggle till I have the .exe working.
Have you ever seen anything like this?
"LINK : fatal error LNK1173: unable to find entrypoint 'DllGetObjHandler' in C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\c2.dll"
I can usually build the project fine but something amiss. Been at this problem for about an hour now and Im getting tired, thought it would help to post the problem.
I'll tell how I made the toggle in source tomorrow, for now Im out.
~Colt
BIG EDIT:
OMG.... All I have to say... I was cleaning the solution through Visual Studio and thought that would work... But no... That happened to be the reason I was getting the error lol
So I manually took the objs out (Like spring cleaning lol) and then built with the batch builder. All is well now lol Time to test that toggle. Wish me luck.
#66
In the player.h file I added mFlying to the player class and made sure that it was public. You need to make it public when you addField() it.
bool mFlying; ///< Are we flying?
Then after adding mFlying, I added to new member function to the header. Placing them by the original updateMove() prototype is probably best.
bool updateRunMove(const Move *move);
bool updateFlightMove(const Move *move);
You will also have to change the original updateMove().
From this===v
//void updateMove(const Move *move);
To this ===v
bool updateMove(const Move *move);
Now for the Player.cc. Kinda like the complex flight, I added a second function. One for flight and the other for Running/Walking.
bool Player::updateMove(const Move* move)
{
if(mFlying)
return(updateFlightMove(move));
else
return(updateRunMove(move));
}
bool Player::updateFlightMove(const Move* move)
{
CODE
}
bool Player::updateRunMove(const Move* move)
{
CODE
}
Dont forget to add mFlying to the addFields, it should look like this:
addField("mFlying", TypeBool, Offset(mFlying, Player) );
So far this hasnt given me any errors but like the noob I am, Im not getting it to work in the game.
I placed in the "default.bind.cs" a toggle and key bind:
function toggleFlight(%val)
{
if(%val)
{
$mFlying = true;
}
else
{
$mFlying = false;
}
}
moveMap.bind( keyboard, e, toggleFlight);
but this doesnt seem to effect anything.
Any thoughts?
Sorry for the mess of a post, dont know how to place codeblocks.
07/10/2007 (9:55 am)
Ok this is what I did to the updateMove()In the player.h file I added mFlying to the player class and made sure that it was public. You need to make it public when you addField() it.
bool mFlying; ///< Are we flying?
Then after adding mFlying, I added to new member function to the header. Placing them by the original updateMove() prototype is probably best.
bool updateRunMove(const Move *move);
bool updateFlightMove(const Move *move);
You will also have to change the original updateMove().
From this===v
//void updateMove(const Move *move);
To this ===v
bool updateMove(const Move *move);
Now for the Player.cc. Kinda like the complex flight, I added a second function. One for flight and the other for Running/Walking.
bool Player::updateMove(const Move* move)
{
if(mFlying)
return(updateFlightMove(move));
else
return(updateRunMove(move));
}
bool Player::updateFlightMove(const Move* move)
{
CODE
}
bool Player::updateRunMove(const Move* move)
{
CODE
}
Dont forget to add mFlying to the addFields, it should look like this:
addField("mFlying", TypeBool, Offset(mFlying, Player) );
So far this hasnt given me any errors but like the noob I am, Im not getting it to work in the game.
I placed in the "default.bind.cs" a toggle and key bind:
function toggleFlight(%val)
{
if(%val)
{
$mFlying = true;
}
else
{
$mFlying = false;
}
}
moveMap.bind( keyboard, e, toggleFlight);
but this doesnt seem to effect anything.
Any thoughts?
Sorry for the mess of a post, dont know how to place codeblocks.
#68
Flight Game Example
and the corresponding code resource:
aiFlyingVehicle C++ Sources
08/14/2007 (5:33 am)
Shameless self promotion, but I'd like to add the Flight Game Example
and the corresponding code resource:
aiFlyingVehicle C++ Sources
#69
Has anyone come up with a true fix to this problem yet? By the way I am only interested in using it for wheeled Vehicles.
I would also like to thank you since your resource really helped me with a problem I was having with dismounting the players.
08/26/2007 (11:58 pm)
Hi I have had the same problem as discribed by Lee Latham and Ehab Yosry Amer with the Drunk Driver. I have tried several things with move tolerances and Ehab's code to no avail. Ehab's code really doesn't cure the problem it just forces the steering to straighten faster but the over steering condition is still there.Has anyone come up with a true fix to this problem yet? By the way I am only interested in using it for wheeled Vehicles.
I would also like to thank you since your resource really helped me with a problem I was having with dismounting the players.
#70
if u r making a racing game, u could fire the event "onReachDestination" after the "dist
OR
if u want the car just to stop, reduce the max distance to whatever value u want NEAR the destination & stop the car by setting mMoveState = ModeStop
please explain a ltl more of the behavior u are annoyed with, so we could pin point the responsible part for it :) incase that my guess was not correct
I hope this helps :)
08/27/2007 (3:18 am)
well, true my code only fixes a part of the problem which prevents the car from going from right to left, but I still have a problem of the strange way the car reaches the destination in BUT I have a hint of how to fix itif (mMoveSlowdown)
{
F32 speed = mMoveSpeed;
F32 dist = mSqrt(xDiff*xDiff + yDiff*yDiff);
F32 maxDist = 15.0; //INCREASED THE MAX DISTANCE TO START BREAKING EARLIER
if (dist < maxDist)
speed *= dist / maxDist;
movePtr->x *= speed;
movePtr->y *= speed;
}if u r making a racing game, u could fire the event "onReachDestination" after the "dist
if u want the car just to stop, reduce the max distance to whatever value u want NEAR the destination & stop the car by setting mMoveState = ModeStop
please explain a ltl more of the behavior u are annoyed with, so we could pin point the responsible part for it :) incase that my guess was not correct
I hope this helps :)
#71
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=6305
it returns the wheels to their direction again of front, instead of keeping the wheels on the direction they were last set on, there is a resistance value that determines how fast should it return to origin
08/27/2007 (3:28 am)
oh & btw I hope u didn't forget about this resourcehttp://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=6305
it returns the wheels to their direction again of front, instead of keeping the wheels on the direction they were last set on, there is a resistance value that determines how fast should it return to origin
#72
Probably just going to need to come up with a solution in my wheeled vehicle code to check for AI control.
08/27/2007 (10:23 am)
Well Ehab I stand a bit corrected. Your fix does infact give a solid solution for the AI Drunk Steering problem, but with the fix comes a problem for human players and steering being more than a little difficult.Probably just going to need to come up with a solution in my wheeled vehicle code to check for AI control.
#73
OR
u could make the resistance variable (I dont know the variable name) visible on script to change the value for each instance of the wheeled vehicle. (Yeah that sound like a better idea) it would also help u make a difference between each driver
08/27/2007 (2:02 pm)
Well, I have a not very good solution, of making a different class for the AI Driver with the differences u want (I think that this idea SUCKS :D :D, but just thinking loudly :))OR
u could make the resistance variable (I dont know the variable name) visible on script to change the value for each instance of the wheeled vehicle. (Yeah that sound like a better idea) it would also help u make a difference between each driver
#74
D
11/13/2007 (1:36 pm)
Thank you very much for this information this is exactly what i was looking for, Since i am new to torque i didnt understand how the player thnx for the explination.D
#75
But... :-) ...I've still got a good bit of the "drunken" effect, where they swerve side to side while accurately navigating the course. I have applied the return-to-center patch to WheeledVehicle. I don't suppose you could point me to some things to mess with to try to remedy this?
Edit: I have helped the situation by reducing maxSteeringAngle = 0.4. You can still see him swerve left/right a bit, but it looks fairly natural. But still I'd like to understand better the paramaters that make it behave this way. Ehab mentioned that the path it followed was "thicker", but I don't understand which part of the code dictates this. An explanation for a non coder would be gratefully appreciated!
11/14/2007 (4:22 pm)
@Ehab: Thanks for posting your code--I've found it extremely helpful. My guys are now driving their cars through waypoints like champs!But... :-) ...I've still got a good bit of the "drunken" effect, where they swerve side to side while accurately navigating the course. I have applied the return-to-center patch to WheeledVehicle. I don't suppose you could point me to some things to mess with to try to remedy this?
Edit: I have helped the situation by reducing maxSteeringAngle = 0.4. You can still see him swerve left/right a bit, but it looks fairly natural. But still I'd like to understand better the paramaters that make it behave this way. Ehab mentioned that the path it followed was "thicker", but I don't understand which part of the code dictates this. An explanation for a non coder would be gratefully appreciated!
#76
this means that the line thickness that the car was moving on is no longer of thickness zero, but will be of thickness of 10
the last last turn is like making an over steer then returning back, It didn't annoy me much so I didn't think abt it.
its something like driving very fast & turn rather quickly not gradually so the car turns more than what u need so u have to turn the other way to put the car in the right direction.
I found it rather cool, since I wasn't making a racing game
11/21/2007 (7:15 am)
I changed the condition fromif (xDiff) [i] TO[/i] if (xDiff < 10.0)meaning that it doesn't have to be EXACTLY on on the same x axis as the point to reach coz that will NEVER happen
this means that the line thickness that the car was moving on is no longer of thickness zero, but will be of thickness of 10
the last last turn is like making an over steer then returning back, It didn't annoy me much so I didn't think abt it.
its something like driving very fast & turn rather quickly not gradually so the car turns more than what u need so u have to turn the other way to put the car in the right direction.
I found it rather cool, since I wasn't making a racing game
#77
Modify the simple flight to not move up or down when you look those directions , but to only move in whatever direction you are looking when you press forward.
11/08/2008 (7:38 pm)
Works great. However, did anyone figure out how to fix this:Modify the simple flight to not move up or down when you look those directions , but to only move in whatever direction you are looking when you press forward.
#78
11/09/2008 (1:04 am)
I would expect that to be a simple matter of binding mouse axes--but I can't say I've tried it.
#79
I'm trying to make a hover board game were the player starts as a guy on a hover board. I want the player to start out as a hover vehicle but every time i try to change the %player = new hovervehicle() and datablock = hoverboard (the name of my hoverboard datablock) in the game.cs file, just like in the racer starter kit, torque crashes. I'm still trying to work on it but if anyone has any reasons to why this is happening please post
11/24/2008 (9:24 pm)
I was wondering if a hover vehicle can be boned and skinned then animated on the activeback and maintainback functions?I'm trying to make a hover board game were the player starts as a guy on a hover board. I want the player to start out as a hover vehicle but every time i try to change the %player = new hovervehicle() and datablock = hoverboard (the name of my hoverboard datablock) in the game.cs file, just like in the racer starter kit, torque crashes. I'm still trying to work on it but if anyone has any reasons to why this is happening please post
#80
The crash is really impossible to say without knowing more about your code that most people would be willing to do. What I can tell you from experience--just keep hacking at it and you'll figure it out. Try isolating the problem further. For example, can you have the player come in as other types of objects (ie. player, wheeledvehicle, etc). Just keep changing out pieces and changing the way you do things until you find the offending logic.
11/24/2008 (10:55 pm)
I don't think the animation would be a major problem. The crash is really impossible to say without knowing more about your code that most people would be willing to do. What I can tell you from experience--just keep hacking at it and you'll figure it out. Try isolating the problem further. For example, can you have the player come in as other types of objects (ie. player, wheeledvehicle, etc). Just keep changing out pieces and changing the way you do things until you find the offending logic.

Torque Owner Colt Carnes
The resource works fine and like a charm but I have a small problem that I have been trying to figure out for about a week now. lol All I need is the simple flight and a way to toggle it so that my player can only walk/run until they meet a requirement or press a button. I tried doing something similar to the complex flight for the AI but instead for the player. That didnt work out so well. lol
So my question is; can some one give me a push into the right direction or maybe an example? I have been looking for this subject for sometime with no avail.
Trying to make a super heros deathmatch game.
Thank you in advance,
~Colt