Plane Flight Model for WheeledFlyingVehicle
by Brian Richardson · 06/15/2005 (12:23 am) · 14 comments
This is the flight model I made for a project that's not going to be finished. So I thought I'd
publish it and maybe someone else can get some use out of it. This implements a standard thrust, lift, drag, gravity flight model that
a plane uses. It's very simplified, it calculates forces on the plane as a whole. It's been tweaked to "feel right" when flying, so it's
definitely not a flight simulation, but a fun arcade dogfighting flight model.
It hasn't been profiled, so there is plenty of room of optimization (for example, not calling updateForcesDriving when you're far above ground.).
This also doesn't contain driving mode vs. flying mode. It is always checking both. So you can just land your plane BF1942 style.
This adds a bunch of new parameters to the wheeledFlyingVehicle datablock. They're explained below in step one. You
can tweak these parameters to get new flying characteristics to your plane.
Updated 6/27/05, Thanks to Robert Rice for pointing out some variable issues!
Step 0: Install Robert Browsers Wheeled Flying Vehicle Resource. It's available here
In wheeledFlyingVehicle.h:
In class WheeledFlyingVehicleData, add these variables to the public section:
In class WheeledFlyingVehicle, add this variable to the private section:
and add these new methods:
In wheeledFlyingVehicle.cc:
Add this to the end of WheeledFlyingVehicleData::WheeledFlyingVehicleData()
Add this to the end of WheeledFlyingVehicleData::initPersistFields()
Add this to the end of WheeledFlyingVehicleData::packData()
Add this to the end of WheeledFlyingVehicleData::unpackData()
Add this line to WheeledFlyingVehicle::WheeledFlyingVehicle:
Replace WheeledFlyingVehicle::updateMove with this:
Replace WheeledFlyingVehicle::updateForces with this:
See the bindGame(), bindEditor() functions? I ran into an interesting bug where the editor would turn the opposite of what you
wanted it to. I'm sure this is a bug in my code somewhere, but I didn't get around to fixing it. Post a solution in the comments if you
find one!
Finally, here's an example datablock:
I just ripped this out of the project I had it working in. So I maybe missing a piece or two, just comment here if you run into any
issues and I'll do my best to help you out.
publish it and maybe someone else can get some use out of it. This implements a standard thrust, lift, drag, gravity flight model that
a plane uses. It's very simplified, it calculates forces on the plane as a whole. It's been tweaked to "feel right" when flying, so it's
definitely not a flight simulation, but a fun arcade dogfighting flight model.
It hasn't been profiled, so there is plenty of room of optimization (for example, not calling updateForcesDriving when you're far above ground.).
This also doesn't contain driving mode vs. flying mode. It is always checking both. So you can just land your plane BF1942 style.
This adds a bunch of new parameters to the wheeledFlyingVehicle datablock. They're explained below in step one. You
can tweak these parameters to get new flying characteristics to your plane.
Updated 6/27/05, Thanks to Robert Rice for pointing out some variable issues!
Step 0: Install Robert Browsers Wheeled Flying Vehicle Resource. It's available here
In wheeledFlyingVehicle.h:
In class WheeledFlyingVehicleData, add these variables to the public section:
F32 liftCoefficient; // used in lift calc
F32 wingArea; // how much lift surface do we have
F32 airDensity; // used in lift calc
F32 dragCoefficient; // drag by this amount
F32 pitchLinForce; // how much force to apply to pitch immediately based on pitch
F32 noseDownCutoff; // below this speed, apply full gravity to torque
F32 noseDownHigh; // above this speed, don't apply any gravity to torque
F32 maxForwardVelocity; // don't apply anymore thrust if we are going this fast.
F32 steeringDecay; // Scale the steering by this amount every tick, effective moves the stick to zero
F32 maneuverCutoff; // Below this speed, you can not pitch/roll
F32 manueverHigh; // Above this speed, you have full manuever ability
F32 propThrustCoeff; // How much thrust does the propellor generate
F32 maneuveringForce; // How much force to apply when changing directionIn class WheeledFlyingVehicle, add this variable to the private section:
F32 mSteeringRoll;
and add these new methods:
void updateForcesFlying(F32 dt); void updateForcesDriving(F32 dt); F32 inputAdjust(const F32 inputAmt);
In wheeledFlyingVehicle.cc:
Add this to the end of WheeledFlyingVehicleData::WheeledFlyingVehicleData()
liftCoefficient = 2.8f;
wingArea = 16.0f;
airDensity = 0.1f;
dragCoefficient = 0.4f;
pitchLinForce = 0.3f;
noseDownCutoff = 50.0f; // below this speed, apply full gravity to torque
noseDownHigh = 200.0f; // above this speed, don't apply any gravity to torque
maxForwardVelocity = 3200.0f; // don't apply anymore thrust if we are going this fast.
steeringDecay = 0.95f; // Scale the steering by this amount every tick, effective moves the stick to zero
maneuverCutoff = 15.0f; // Below this speed, you can not pitch/roll
manueverHigh = 65.0f; // Above this speed, you have full manuever ability
propThrustCoeff = 0.3;
maneuveringForce = 120000; Add this to the end of WheeledFlyingVehicleData::initPersistFields()
addField("maneuveringForce", TypeF32, Offset(maneuveringForce, WheeledFlyingVehicleData));
addField("liftCoefficient", TypeF32, Offset(liftCoefficient, WheeledFlyingVehicleData));
addField("wingArea", TypeF32, Offset(wingArea, WheeledFlyingVehicleData));
addField("airDensity", TypeF32, Offset(airDensity, WheeledFlyingVehicleData));
addField("dragCoefficient", TypeF32, Offset(dragCoefficient, WheeledFlyingVehicleData));
addField("pitchLinForce", TypeF32, Offset(pitchLinForce, WheeledFlyingVehicleData));
addField("noseDownCutoff", TypeF32, Offset(noseDownCutoff, WheeledFlyingVehicleData));
addField("noseDownHigh", TypeF32, Offset(noseDownHigh, WheeledFlyingVehicleData));
addField("maxForwardVelocity", TypeF32, Offset(maxForwardVelocity, WheeledFlyingVehicleData));
addField("steeringDecay", TypeF32, Offset(steeringDecay, WheeledFlyingVehicleData));
addField("propThrustCoeff", TypeF32, Offset(propThrustCoeff, WheeledFlyingVehicleData));Add this to the end of WheeledFlyingVehicleData::packData()
stream->write(maneuveringForce); stream->write(liftCoefficient); stream->write(wingArea); stream->write(airDensity); stream->write(dragCoefficient); stream->write(pitchLinForce); stream->write(noseDownCutoff); stream->write(noseDownHigh); stream->write(maxForwardVelocity); stream->write(steeringDecay); stream->write(propThrustCoeff);
Add this to the end of WheeledFlyingVehicleData::unpackData()
stream->read(&maneuveringForce); stream->read(&liftCoefficient); stream->read(&wingArea); stream->read(&airDensity); stream->read(&dragCoefficient); stream->read(&pitchLinForce); stream->read(&noseDownCutoff); stream->read(&noseDownHigh); stream->read(&maxForwardVelocity); stream->read(&steeringDecay); stream->read(&propThrustCoeff);
Add this line to WheeledFlyingVehicle::WheeledFlyingVehicle:
mSteeringRoll = 0;
Replace WheeledFlyingVehicle::updateMove with this:
void WheeledFlyingVehicle::updateMove(const Move* move)
{
Move newMove(*move);
newMove.pitch *= -1;
Parent::updateMove(&newMove);
// Roll
mSteeringRoll = mClampF(mSteeringRoll + move->roll,-mDataBlock->maxSteeringAngle,
mDataBlock->maxSteeringAngle);
if (move == &NullMove)
mSteering.set(0,0);
// Check the mission area to get the factor for the flight ceiling
mCeilingFactor = 1.0f;
MissionArea * obj = dynamic_cast<MissionArea*>(Sim::findObject("MissionArea"));
if (obj != NULL)
{
F32 flightCeiling = obj->getFlightCeiling();
F32 ceilingRange = obj->getFlightCeilingRange();
if (mRigid.linPosition.z > flightCeiling)
{
// Thrust starts to fade at the ceiling, and is 0 at ceil + range
if (ceilingRange == 0)
{
mCeilingFactor = 0;
}
else
{
mCeilingFactor = 1.0f - ((mRigid.linPosition.z - flightCeiling) / (flightCeiling + ceilingRange));
if (mCeilingFactor < 0.0f)
mCeilingFactor = 0.0f;
}
}
}
if (mCeilingFactor != 1.0f)
mJetting = false;
mThrust.x = move->x;
mThrust.y = mClampF(mThrust.y + move->y, 0, 1);
mSteering.x *= mDataBlock->steeringDecay;
mSteering.y *= mDataBlock->steeringDecay;
mSteeringRoll *= mDataBlock->steeringDecay;
mThrust.y *= 0.985;
if (mThrust.y < 0.1)
mThrust.y = 0;
if (getDamageValue() > 0.99)
mThrust.y = 0;
}Replace WheeledFlyingVehicle::updateForces with this:
void WheeledFlyingVehicle::updateForces(F32 dt)
{
if (getDamageValue() < 0.99f) {
updateForcesDriving(dt);
updateForcesFlying(dt);
} else {
mRigid.force = Point3F(0, 0, sWheeledFlyingVehicleGravity * mRigid.mass * mGravityMod);
mRigid.torque = Point3F(0, 0, 0);
}
}
void WheeledFlyingVehicle::updateForcesDriving(F32 dt)
{
extendWheels();
F32 oneOverSprungMass = 1 / (mMass * 0.8);
F32 aMomentum = mMass / mDataBlock->wheelCount;
// Get the current matrix and extact vectors
MatrixF currMatrix;
mRigid.getTransform(&currMatrix);
Point3F bx,by,bz;
currMatrix.getColumn(0,&bx);
currMatrix.getColumn(1,&by);
currMatrix.getColumn(2,&bz);
// Steering angles from current steering wheel position
F32 quadraticSteering = -(mSteering.x * mFabs(mSteering.x));
F32 cosSteering,sinSteering;
mSinCos(quadraticSteering, sinSteering, cosSteering);
// Calculate Engine and brake torque values used later by in
// wheel calculations.
F32 engineTorque,brakeVel;
if (mBraking) {
brakeVel = (mDataBlock->brakeTorque / aMomentum) * dt;
engineTorque = 0;
}
else {
if (mThrottle) {
engineTorque = mDataBlock->engineTorque * mThrottle;
brakeVel = 0;
// Double the engineTorque to help out the jets
if (mThrottle > 0 && mJetting)
engineTorque *= 2;
}
else {
// Engine break.
brakeVel = (mDataBlock->engineBrake / aMomentum) * dt;
engineTorque = 0;
}
}
// Integrate forces, we'll do this ourselves here instead of
// relying on the rigid class which does it during movement.
Wheel* wend = &mWheel[mDataBlock->wheelCount];
mRigid.force.set(0, 0, 0);
mRigid.torque.set(0, 0, 0);
// Calculate vertical load for friction. Divide up the spring
// forces across all the wheels that are in contact with
// the ground.
U32 contactCount = 0;
F32 verticalLoad = 0;
for (Wheel* wheel = mWheel; wheel < wend; wheel++) {
if (wheel->tire && wheel->spring && wheel->surface.contact) {
verticalLoad += wheel->spring->force * (1 - wheel->extension);
contactCount++;
}
}
if (contactCount)
verticalLoad /= contactCount;
// Sum up spring and wheel torque forces
for (Wheel* wheel = mWheel; wheel < wend; wheel++) {
if (!wheel->tire || !wheel->spring)
continue;
F32 Fy = 0;
if (wheel->surface.contact) {
// First, let's compute the wheel's position, and worldspace velocity
Point3F pos, r, localVel;
currMatrix.mulP(wheel->data->pos, &pos);
mRigid.getOriginVector(pos,&r);
mRigid.getVelocity(r, &localVel);
// Spring force & damping
F32 spring = wheel->spring->force * (1 - wheel->extension);
F32 damping = wheel->spring->damping * -(mDot(bz, localVel) / wheel->spring->length);
if (damping < 0)
damping = 0;
// Anti-sway force based on difference in suspension extension
F32 antiSway = 0;
if (wheel->data->opposite != -1) {
Wheel* oppositeWheel = &mWheel[wheel->data->opposite];
if (oppositeWheel->surface.contact)
antiSway = ((oppositeWheel->extension - wheel->extension) *
wheel->spring->antiSway);
if (antiSway < 0)
antiSway = 0;
}
// Spring forces act straight up and are applied at the
// spring's root position.
Point3F t, forceVector = bz * (spring + damping + antiSway);
mCross(r, forceVector, &t);
mRigid.torque += t;
mRigid.force += forceVector;
// Tire direction vectors perpendicular to surface normal
Point3F wheelXVec = bx * cosSteering;
wheelXVec += by * sinSteering * wheel->steering;
Point3F tireX, tireY;
mCross(wheel->surface.normal, wheelXVec, &tireY);
tireY.normalize();
mCross(tireY, wheel->surface.normal, &tireX);
tireX.normalize();
// Velocity of tire at the surface contact
Point3F wheelContact, wheelVelocity;
mRigid.getOriginVector(wheel->surface.pos,&wheelContact);
mRigid.getVelocity(wheelContact, &wheelVelocity);
F32 xVelocity = mDot(tireX, wheelVelocity);
F32 yVelocity = mDot(tireY, wheelVelocity);
// Tires act as springs and generate lateral and longitudinal
// forces to move the vehicle. These distortion/spring forces
// are what convert wheel angular velocity into forces that
// act on the rigid body.
// Longitudinal tire deformation force
F32 ddy = (wheel->avel * wheel->tire->radius - yVelocity) -
wheel->tire->longitudinalRelaxation *
mFabs(wheel->avel) * wheel->Dy;
wheel->Dy += ddy * dt;
Fy = (wheel->tire->longitudinalForce * wheel->Dy +
wheel->tire->longitudinalDamping * ddy);
// Lateral tire deformation force
F32 ddx = xVelocity - wheel->tire->lateralRelaxation *
mFabs(wheel->avel) * wheel->Dx;
wheel->Dx += ddx * dt;
F32 Fx = -(wheel->tire->lateralForce * wheel->Dx +
wheel->tire->lateralDamping * ddx);
// Vertical load on the tire
verticalLoad = spring + damping + antiSway;
if (verticalLoad < 0)
verticalLoad = 0;
// Adjust tire forces based on friction
F32 surfaceFriction = 1;
F32 mu = surfaceFriction * (wheel->slipping)?
wheel->tire->kineticFriction:
wheel->tire->staticFriction;
F32 Fn = verticalLoad * mu; Fn *= Fn;
F32 Fw = Fx * Fx + Fy * Fy;
if (Fw > Fn) {
F32 K = mSqrt(Fn / Fw);
Fy *= K;
Fx *= K;
wheel->Dy *= K;
wheel->Dx *= K;
wheel->slip = 1 - K;
wheel->slipping = true;
}
else {
wheel->slipping = false;
wheel->slip = 0;
}
// Tire forces act through the tire direction vectors parallel
// to the surface and are applied at the wheel hub.
forceVector = (tireX * Fx) + (tireY * Fy);
pos -= bz * (wheel->spring->length * wheel->extension);
mRigid.getOriginVector(pos,&r);
mCross(r, forceVector, &t);
mRigid.torque += t;
mRigid.force += forceVector;
}
else {
// Wheel not in contact with the ground
wheel->torqueScale = 0;
wheel->slip = 0;
// Relax the tire deformation
wheel->Dy += (-wheel->tire->longitudinalRelaxation *
mFabs(wheel->avel) * wheel->Dy) * dt;
wheel->Dx += (-wheel->tire->lateralRelaxation *
mFabs(wheel->avel) * wheel->Dx) * dt;
}
// Adjust the wheel's angular velocity based on engine torque
// and tire deformation forces.
if (wheel->powered) {
F32 maxAvel = mDataBlock->maxWheelSpeed / wheel->tire->radius;
wheel->torqueScale = (mFabs(wheel->avel) > maxAvel) ? 0 :
1 - (mFabs(wheel->avel) / maxAvel);
}
else
wheel->torqueScale = 0;
wheel->avel += (((wheel->torqueScale * engineTorque) - Fy *
wheel->tire->radius) / aMomentum) * dt;
// Adjust the wheel's angular velocity based on break torque.
// This is done after avel update to make sure we come to a
// complete stop.
if (brakeVel > mFabs(wheel->avel))
wheel->avel = 0;
else
if (wheel->avel > 0)
wheel->avel -= brakeVel;
else
wheel->avel += brakeVel;
}
// Jet Force
if (mJetting)
mRigid.force += by * mDataBlock->jetForce;
// Container drag & buoyancy
mRigid.force += Point3F(0, 0, -mBuoyancy * sWheeledFlyingVehicleGravity * mRigid.mass);
mRigid.force -= mRigid.linVelocity * mDrag;
mRigid.torque -= mRigid.angMomentum * mDrag;
// If we've added anything other than gravity, then we're no
// longer at rest. Could test this a little more efficiently...
if (mRigid.atRest && (mRigid.force.len() || mRigid.torque.len()))
mRigid.atRest = false;
// Integrate and update velocity
mRigid.linMomentum += mRigid.force * dt;
mRigid.angMomentum += mRigid.torque * dt;
mRigid.updateVelocity();
// Since we've already done all the work, just need to clear this out.
mRigid.force.set(0, 0, 0);
mRigid.torque.set(0, 0, 0);
// If we're still atRest, make sure we're not accumulating anything
if (mRigid.atRest)
mRigid.setAtRest();
}
F32 WheeledFlyingVehicle::inputAdjust(const F32 inputAmt)
{
if (inputAmt != 0) {
return (inputAmt*inputAmt) * (inputAmt / mFabs(inputAmt));
} else {
return 0;
}
}
void WheeledFlyingVehicle::updateForcesFlying(F32 dt)
{
// Get our orientation
MatrixF currPosMat;
mRigid.getTransform(&currPosMat);
mRigid.atRest = false;
Point3F massCenter;
currPosMat.mulP(mDataBlock->massCenter,&massCenter);
Point3F xv,yv,zv;
currPosMat.getColumn(0,&xv);
currPosMat.getColumn(1,&yv);
currPosMat.getColumn(2,&zv);
F32 speed = mRigid.linVelocity.len();
F32 forwardVelocity = mDot(mRigid.linVelocity, yv);
// Force 1: Gravity (linear)
F32 downForceMag = sWheeledFlyingVehicleGravity * mRigid.mass * mGravityMod;
Point3F force(0, 0, downForceMag);
// Force 2: Thrust
if ((forwardVelocity < mDataBlock->maxForwardVelocity) && (mThrust.y > 0))
force += yv * (mThrust.y * mDataBlock->maneuveringForce * mCeilingFactor);
// Force 3: Lift = (LiftCoEff * (0.5 * airDensity * velocity^2 * wing area)
F32 fv = forwardVelocity*forwardVelocity;
F32 liftDrag = (0.5 * mDataBlock->airDensity * fv * mDataBlock->wingArea);
F32 liftForce = mDataBlock->liftCoefficient * liftDrag;
force += zv * liftForce;
F32 tUp = mClampF(mFabs(liftForce / downForceMag), 0, 1);
tailUpTarget = tUp * tUp;
// Force 1: Gravity (angular)
Point3F torque(0, 0, 0);
F32 cutoffPoint = 20;
F32 positiveLift = liftForce + downForceMag;
if (positiveLift < cutoffPoint) {
F32 noseDown = mDot(yv, Point3F(0, 0, -1));
F32 noseDownCoEff = cutoffPoint - positiveLift;
noseDownCoEff = mClampF(noseDownCoEff / 100000, 0, 1);
mCross(massCenter - mRigid.linPosition, Point3F(0, 0, (1 - noseDown) * downForceMag * noseDownCoEff), torque);
}
// Force 4: Drag
F32 dragForce = (mDataBlock->dragCoefficient * (mRigid.linVelocity.magnitudeSafe()*mRigid.linVelocity.magnitudeSafe()));
force -= dragForce * mRigid.linVelocity;
torque -= mRigid.angMomentum * mDataBlock->rotationalDrag;
// We can't have full pitch contribution if we are not flying quick enough.
F32 manueverCoeff = 1.0f;
if (forwardVelocity <= mDataBlock->maneuverCutoff) {
manueverCoeff = 0.0f;
} else {
F32 range = mDataBlock->manueverHigh - mDataBlock->maneuverCutoff;
manueverCoeff = mClampF((forwardVelocity - mDataBlock->maneuverCutoff) / range, 0.0f, 1.0f);
}
// Pitch control (up/down)
F32 pitchAmt = inputAdjust(mSteering.y / mDataBlock->maxSteeringAngle); // normalize angle 0..1
torque -= xv * pitchAmt * mDataBlock->steeringForce * manueverCoeff;
force -= zv * pitchAmt * mDataBlock->pitchLinForce; // let's immediately apply some force here
// Roll control
F32 rollAmt = inputAdjust(mSteeringRoll / mDataBlock->maxSteeringAngle);
torque += yv * rollAmt * mDataBlock->steeringRollForce * manueverCoeff;
// Yaw control
F32 yawAmt = inputAdjust(mSteering.x / mDataBlock->maxSteeringAngle);
torque += zv * yawAmt * mDataBlock->steeringForce * manueverCoeff;
// Let's update our move stuff
mRigid.force = force;
mRigid.torque = torque;
}Finally, add this stuff to the end of your default.bind.cs file:function moveleft(%val)
{
$mvLeftAction = %val;
}
function moveright(%val)
{
$mvRightAction = %val;
}
function moveforward(%val)
{
$mvForwardAction = %val;
}
function movebackward(%val)
{
$mvBackwardAction = %val;
}
function rollLeft( %val )
{
$mvRollLeftSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}
function rollRight( %val )
{
$mvRollRightSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}
function turnLeft( %val )
{
$mvYawLeftSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}
function turnRight( %val )
{
$mvYawRightSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}
function panUp( %val )
{
$mvPitchDownSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}
function panDown( %val )
{
$mvPitchUpSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}
// Mouse steering functions
//
function getMouseAdjustAmount(%val)
{
// based on a default camera fov of 90'
return(%val * ($cameraFov / 90) * 0.0025);
}
function yaw(%val)
{
$mvYaw += getMouseAdjustAmount(%val);
}
function pitch(%val)
{
$mvPitch += getMouseAdjustAmount(%val);
}
function roll(%val)
{
$mvRoll += getMouseAdjustAmount(%val);
}
// We want different behavior for the keys and mouse in game then in editor mode.
function bindGame()
{
moveMap.bind(keyboard, left, rollLeft);
moveMap.bind(keyboard, right, rollRight);
moveMap.bind( mouse, xaxis, roll );
moveMap.bind(keyboard, a, turnLeft);
moveMap.bind(keyboard, d, turnRight);
}
function bindEditor()
{
moveMap.bind(keyboard, left, turnRight);
moveMap.bind(keyboard, right, turnLeft);
moveMap.bind(mouse, xaxis, yaw );
moveMap.bind(keyboard, a, moveLeft);
moveMap.bind(keyboard, d, moveRight);
}
bindGame();
// These binding do not change
moveMap.bind( keyboard, w, moveforward );
moveMap.bind( keyboard, s, movebackward );
moveMap.bind( mouse, yaxis, pitch );
moveMap.bind(keyboard, up, panUp);
moveMap.bind(keyboard, down, panDown);See the bindGame(), bindEditor() functions? I ran into an interesting bug where the editor would turn the opposite of what you
wanted it to. I'm sure this is a bug in my code somewhere, but I didn't get around to fixing it. Post a solution in the comments if you
find one!
Finally, here's an example datablock:
datablock WheeledFlyingVehicleData(AirCraft)
{
spawnOffset = "0 0 2";
emap = true;
category = "Vehicles";
shapeFile = "~/data/shapes/vehicles/dev_aircraft/dev_aircraft.dts";
multipassenger = false;
computeCRC = true;
debrisShapeName = "~/data/shapes/vehicles/dev_aircraft/dev_aircraft.dts";
debris = AircraftDebris;
renderWhenDestroyed = false;
debris = PlaneDebris;
className = "Plane";
emap = true;
explosion = PlaneWeaponExplosion;
mountPose[0] = sitting;
maxDamage = 1.5;
destroyedLevel = 1.0;
maxSteeringAngle = 0.785; // Maximum steering angle, should match animation
integration = 6; // Force integration time: TickSec/Rate
// 3rd person camera settings
cameraRoll = false; // Roll the camera with the vehicle
cameraMaxDist = 5; // Far distance from vehicle
cameraOffset = 1.5; // Vertical offset from camera mount point
cameraLag = 0.00; // Velocity lag of camera
cameraDecay = 0.00; // Decay per sec. rate of velocity lag
bodyFriction = 9.4;
bodyRestitution = 0.1;
minImpactSpeed = 5; // Impacts over this invoke the script callback
softImpactSpeed = 5; // Play SoftImpact Sound
hardImpactSpeed = 15; // Play HardImpact Sound
// Engine
engineTorque = 65000; // Engine power
engineBrake = 1000; // Braking when throttle is 0
brakeTorque = 20000; // When brakes are applied
maxWheelSpeed = 150; // Engine scale by current speed / max speed
// Energy
//maxEnergy = 100;
jetForce = 3000;
minJetEnergy = 30;
jetEnergyDrain = 2;
// Sounds
engineSound = PlaneEngineSound;
spawnOffset = "0 0 1";
ultipassenger = false;
ComputeCRC = true;
renderWhenDestroyed = false;
mountPose[0] = sitting;
drag = 0.15;
density = 1.0;
minMountDist = 6;
//maxDamage = 90.00;
//DestroyedLevel = 90.00;
isShielded = true;
EnergyPerDamagePoint = 160;
MaxEnergy = 280; // Afterburner and any energy weapon pool
MinDrag = 88; // Linear Drag (eventually slows you down when not thrusting...constant drag)
RechargeRate = 5.0;
maxAutoSpeed = 4; // Autostabilizer kicks in when less than this speed. (meters/second)
autoAngularForce = 100; // Angular stabilizer force (this force levels you out when autostabilizer kicks in)
autoLinearForce = 300; // Linear stabilzer force (this slows you down when autostabilizer kicks in)
autoInputDamping = 1.0;// Dampen control input so you don't whack out at very slow speeds
// Maneuvering Information
// RFB -> need a steering angle specific to flight since flight and driving steering are so different
maxFlightSteeringAngle = 0.785; // lower numbers are more manueverable
//MaxSteeringAngle = 4.2; // Max radians you can rotate the wheel. Smaller number is more maneuverable.
HorizontalSurfaceForce = 350;// Horizontal center "wing" (provides "bite" into the wind for climbing/diving and turning)
VerticalSurfaceForce = 100; // Vertical center "wing" (controls side slip. lower numbers make MORE slide.)
// New flight model parameters
mass = 2203;
massCenter = "0.0 1.0 0";
liftCoefficient = 2.0; // Lift coefficient
wingArea = 16; // Wing area (used in lift calc)
airDensity = 1; // Air density (used in lift calc)
dragCoefficient = 0.3; // Drag
RotationalDrag = 3; // Anguler Drag (dampens the drift after you stop moving the mouse...also tumble drag)
ManeuveringForce = 120000; // Thrust forvce
SteeringForce = 60000; // Used for pitch/yaw
SteeringRollForce = 200000; // Roll force
pitchLinForce = 0; // Apply this amount of force based on pitch
noseDownCutoff = 500; // below this speed, apply full gravity to torque
noseDownHigh = 1000; // above this speed, don't apply any gravity to torque
maxForwardVelocity = 3200; // don't apply anymore thrust if we are going this fast.
steeringDecay = 0.95; // Scale the steering by this amount every tick, effective moves the stick to zero
// End
collisionTol = 0.1; // Collision distance tolerance
contactTol = 0.1; // Contact velocity tolerance
RollForce = 820; // Auto-roll (self-correction to right you after you roll/invert)
HoverHeight = 1.0; // Height off the ground at rest
CreateHoverHeight = 1.0; // Height off the ground when created
// Rigid body
//Mass = 500; // Mass of the vehicle
//BodyFriction = 0; // Don't mess with this.
//BodyRestitution = 0.8;// When you hit the ground, how much you rebound. (between 0 and 1)
MinRollSpeed = 0; // Don't mess with this.
MinImpactSpeed = 0; // If hit ground at speed above this then it's an impact. Meters/second
SoftImpactSpeed = 10; // Sound hooks. This is the soft hit.
HardImpactSpeed = 25; // Sound hooks. This is the hard hit.
SpeedDamageScale = 0.04;
collDamageThresholdVel = 20.0;
collDamageMultiplier = 0.02;
// Contrail
minTrailSpeed = 75; // The speed your contrail shows up at.
TrailEmitter = ContrailEmitter;
TrailEmitterOffset = "0.0 0.0 0.0";
TrailEmitterHeight = 0;
TrailEmitterFreqMod = 2.0;
// Damage
damageEmitter[0] = DamageEmitter3;
damageEmitter[1] = DamageEmitter2;
damageEmitter[2] = DamageEmitter1;
damageEmitterOffset[0] = "0.0 -3.0 0.0 ";
damageEmitterOffset[1] = "0.0 0.0 -1.0";
damageEmitterOffset[2] = "0.0 1.0 1.0";
damageLevelTolerance[0] = 0.1;
damageLevelTolerance[1] = 0.5;
numDmgEmitterAreas = 3;
// Inventory
maxInv[PlaneAmmo] = 500;
//------------------------------------------------------------
// Sound Velocities
// Velocities at which Water Impact sounds will be triggered
SoftSplashSound = 15.0;
MediumSplashSoundVelocity = 30.0;
HardSplashSoundVelocity = 60.0;
ExitSplashSoundVelocity = 20.0;
// RFB -> added
modeChangeEnergyDrain = 30; // Energy per mode change
minModeChangeEnergy = 0;
minModeChangeSpeed = 0;
maxModeChangeSpeed = 999;
modeChangeDelay = 30; // Delay time in ticks
createMode = 0;
// <- RFB
};I just ripped this out of the project I had it working in. So I maybe missing a piece or two, just comment here if you run into any
issues and I'll do my best to help you out.
About the author
#2
Thanks for the resource!
Tim
06/15/2005 (7:00 am)
I'll have to give this a try... looks very promising.Thanks for the resource!
Tim
#3
Thanks!!
06/15/2005 (7:09 am)
This looks to be a great resource. However, when I install Robert Browsers Wheeled Flying Vehicle Resource I just get a static shape (added through World Creator). Can anyone give me a clue what do next, or what I have done wrong?Thanks!!
#4
If you followed the resource correctly, it probably is not a static shape. First double check your changes to make sure you followed the resource correctly. If you feel as though you did everything correct try this...
Before you launch the mission go into options and controls. Make sure that the thrust and brake are mapped to keys... then launch the mission.
When you move the mouse, do the wheels move?
Tim
06/15/2005 (7:12 am)
Steve,If you followed the resource correctly, it probably is not a static shape. First double check your changes to make sure you followed the resource correctly. If you feel as though you did everything correct try this...
Before you launch the mission go into options and controls. Make sure that the thrust and brake are mapped to keys... then launch the mission.
When you move the mouse, do the wheels move?
Tim
#5
Managed to get Robert Browsers Wheeled Flying Resource working with some messing about last night. Thanks!!
06/16/2005 (1:54 am)
@Tim Managed to get Robert Browsers Wheeled Flying Resource working with some messing about last night. Thanks!!
#6
06/23/2005 (9:56 pm)
So sweet! Nice job robert and bzzt.
#7
06/25/2005 (9:07 am)
Has anyone gotten this to work? I got nothing but 1/2 dozen undeclared identifier errors.
#8
Mail me (bzzt@knowhere.net) your error log so I can see what I need to add to the resource.
06/26/2005 (7:12 am)
@Robert,Mail me (bzzt@knowhere.net) your error log so I can see what I need to add to the resource.
#9
I think it would be important to note what version of TGE you are using. 1.3? 1.4(head)?
I got it to work fine in TGE 1.3
06/26/2005 (7:14 am)
@Robert, I think it would be important to note what version of TGE you are using. 1.3? 1.4(head)?
I got it to work fine in TGE 1.3
#10
06/26/2005 (9:46 am)
Brian, I just sent you an email with the changes I made to get it to compile, along with another question. Thanks!
#11
Which corresponds to this line:
I searched the .h and .cc file and did not find this tailUpTarget anywhere.
11/15/2005 (9:10 am)
When implementing this Mod, I ran into an error:Compiling... wheeledFlyingVehicle.cc C:\Torque\SDK\engine\game\vehicles\wheeledFlyingVehicle.cc(1527) : error C2065: 'tailUpTarget' : undeclared identifier Error executing cl.exe. torqueDemo.exe - 1 error(s), 0 warning(s)
Which corresponds to this line:
tailUpTarget = tUp * tUp;
I searched the .h and .cc file and did not find this tailUpTarget anywhere.
#12
04/25/2006 (8:12 pm)
Did anyone get this working with 1.4, if so please could you add the changed .cc and .h file resource here, or add it as a zip.. I havent been able to get this working with the wheeledFyingV resource as of yet, but Im not so good at the engine changes...Many thanks in Advance..
#13
Now i want to use it as a fighter plane and add weopon to its both wings.
can any one please help me out in this matter.
06/28/2006 (6:27 am)
Hi people, I got my Wheeled Flying Vehicle flying. Now i want to use it as a fighter plane and add weopon to its both wings.
can any one please help me out in this matter.
#14
Now if i thrust up, I am at max speed instantly and cannot control the plane well at all.
01/28/2007 (6:52 am)
Sorry, just tried this and managed to get it to work with a few minor hacks. The static shape issue is something with the datablock. I managed to fix it, but the physics and workings of the plane IMHO were worse than the original. :( Now if i thrust up, I am at max speed instantly and cannot control the plane well at all.
Torque Owner Robert Rice
Default Studio Name