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
#2
01/30/2005 (11:37 pm)
Thanks for sharing this. :)
#3
It's not very hard if you use Windows. I just get the parts I want copied, then paste them into WordPad. Then I copy from there and paste into Visual Studio. No formatting errors, works great.
Edit: God, spelling.
02/02/2005 (10:09 am)
Stephen,It's not very hard if you use Windows. I just get the parts I want copied, then paste them into WordPad. Then I copy from there and paste into Visual Studio. No formatting errors, works great.
Edit: God, spelling.
#4
02/02/2005 (11:04 am)
@Stefan: Hmm, I'll have to try that. I normally cut/paste directly into a "normal" text editor (UltraEdit in my case), but that doesn't capture the return characters at ends of lines, forcing me to go through and hit return at the end of each original line. Thanks!
#5
nonetheless, great resource indeed! This will definiately get me a good start. Thanks!
[edit]
@Stephan, Stefan:
ah, neato trick. Copy into wordpad (if you have windows of course....), and then recopy what's in wordpad and copy back into notepad. Works like a cinch =D
@Bruno
Question: If i need complex flight, do I need the section for simple flight as well? sorry seems kinda dumb of me >.<
also, while reading the inserts, i notced the line you said to put:
sFlyingVehicleGravity = 0;
around line 36 - i was thinking maybe what the type is? All the others are static F32/U32 (what do the types mean anyway? Is there a documentation explaining them?) Eclipse came up with flags without the types..
[/edit]
[edit]
wow, how much more noobish can i get. it was already declared >.<
[/edit]
Cool, got it to compile fine. Nice job! On to scripts...
02/02/2005 (1:22 pm)
Ehe, I just copyt eacah individual line....nonetheless, great resource indeed! This will definiately get me a good start. Thanks!
[edit]
@Stephan, Stefan:
ah, neato trick. Copy into wordpad (if you have windows of course....), and then recopy what's in wordpad and copy back into notepad. Works like a cinch =D
@Bruno
Question: If i need complex flight, do I need the section for simple flight as well? sorry seems kinda dumb of me >.<
also, while reading the inserts, i notced the line you said to put:
sFlyingVehicleGravity = 0;
around line 36 - i was thinking maybe what the type is? All the others are static F32/U32 (what do the types mean anyway? Is there a documentation explaining them?) Eclipse came up with flags without the types..
[/edit]
[edit]
wow, how much more noobish can i get. it was already declared >.<
[/edit]
Cool, got it to compile fine. Nice job! On to scripts...
#6
Since I got a new website, I'll try posting the code over there. But the problem is : I use a Mac, so the line breaks will still be a problem. I'd do what SLundmark sugested, using wordpad. That's what I use when converting scripts from Mac to PCs.
@Josiah
Glad you made it. F32 and U32 mean respectively, a 32bit float and an unsigned 32bit integer. People do that in order to garantee that you'll work with numbers that are the same size on diferent platforms. Using int, long, float and double won't garantee that kind of portability
Also, if you only need complex flight, you may leave simple flight out.
02/02/2005 (2:38 pm)
@Stephen ZeppSince I got a new website, I'll try posting the code over there. But the problem is : I use a Mac, so the line breaks will still be a problem. I'd do what SLundmark sugested, using wordpad. That's what I use when converting scripts from Mac to PCs.
@Josiah
Glad you made it. F32 and U32 mean respectively, a 32bit float and an unsigned 32bit integer. People do that in order to garantee that you'll work with numbers that are the same size on diferent platforms. Using int, long, float and double won't garantee that kind of portability
Also, if you only need complex flight, you may leave simple flight out.
#7
02/03/2005 (10:22 pm)
Very cool resource. Although I don't need flight in my particular project I imagine that alot of other games will have a use for this. Thank you Bruno!
#8
I've been out of the game-business for months now, but keep on checking here regularly ;)
Really nice to see people are still using my contributions :)
02/05/2005 (9:39 am)
Haa! thank you very much for mentioning me :DI've been out of the game-business for months now, but keep on checking here regularly ;)
Really nice to see people are still using my contributions :)
#9
02/08/2005 (1:38 pm)
Wow great resource. Thank YOU!!
#10
Now all i need to do is 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.
My guy is going to be flying a disk, carpet or what ever else he decides to jump on and fly around with.
02/24/2005 (6:42 pm)
Nice, this gave me a head start.Now all i need to do is 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.
My guy is going to be flying a disk, carpet or what ever else he decides to jump on and fly around with.
#11
03/25/2005 (4:14 pm)
Thanks for posting this resource.
#12
04/19/2005 (10:58 am)
You guys are all absolutely amazing to me. Thanks for posting this!
#13
Where do you put the code listed below? You state the exact file for everything else, but I'm dumb and don't know where to put the AI mounting code.
Then dumb question #2 would be even easier. Which file holds the datablock information? Thanks so much for helping me figure out this easy stuff.
04/19/2005 (11:29 am)
Okay, I'm a dumb n00b. I can take that. So here's my question:Where do you put the code listed below? You state the exact file for everything else, but I'm dumb and don't know where to put the AI mounting code.
Quote:
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().
Then dumb question #2 would be even easier. Which file holds the datablock information? Thanks so much for helping me figure out this easy stuff.
#14
Q1) Actually there's no predefined place to put that. It all depends on your game. If you are making a racing game where it begins with the bots inside the vehicle, then you create the bots, create the vehicles and mount the first in the latter. If you are making a "Speed Racer" style of racing where people first run to the vehicles then you might put it in your onCollision function or in your ReachDestination
Q2) That will be in the file where you define the vehicle :-) I beleive that in the starter.racing mission, that file is car.cs.
04/19/2005 (1:06 pm)
@Steve Marshall :Q1) Actually there's no predefined place to put that. It all depends on your game. If you are making a racing game where it begins with the bots inside the vehicle, then you create the bots, create the vehicles and mount the first in the latter. If you are making a "Speed Racer" style of racing where people first run to the vehicles then you might put it in your onCollision function or in your ReachDestination
Q2) That will be in the file where you define the vehicle :-) I beleive that in the starter.racing mission, that file is car.cs.
#19
11/14/2005 (5:20 pm)
Works great thanks for your time!!
#20
01/16/2006 (4:46 pm)
What an outstanding resource! Thanks a lot. A person on my project did something similar with all resources relating to melee combat. I would love to see one for NPCs. 
Torque 3D Owner Stephen Zepp
My only suggestion would be to host the file somewhere and provide a link...that is a lot to cut/paste, especially with how hard it is to reformat code from the forums.