123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "T3D/vehicles/flyingVehicle.h"
- #include "app/game.h"
- #include "math/mMath.h"
- #include "console/simBase.h"
- #include "console/console.h"
- #include "console/consoleTypes.h"
- #include "console/engineAPI.h"
- #include "collision/clippedPolyList.h"
- #include "collision/planeExtractor.h"
- #include "core/stream/bitStream.h"
- #include "core/dnet.h"
- #include "T3D/gameBase/gameConnection.h"
- #include "ts/tsShapeInstance.h"
- #include "T3D/fx/particleEmitter.h"
- #include "sfx/sfxSystem.h"
- #include "sfx/sfxProfile.h"
- #include "sfx/sfxSource.h"
- #include "T3D/missionArea.h"
- //----------------------------------------------------------------------------
- const static U32 sCollisionMoveMask = ( TerrainObjectType | WaterObjectType |
- PlayerObjectType | StaticShapeObjectType |
- VehicleObjectType | VehicleBlockerObjectType );
-
- static U32 sServerCollisionMask = sCollisionMoveMask; // ItemObjectType
- static U32 sClientCollisionMask = sCollisionMoveMask;
- typedef FlyingVehicleData::Sounds engineSounds;
- DefineEnumType(engineSounds);
- ImplementEnumType(engineSounds, "enum types.\n"
- "@ingroup VehicleData\n\n")
- { engineSounds::JetSound, "JetSound", "..." },
- { engineSounds::EngineSound, "EngineSound", "..." },
- EndImplementEnumType;
- //
- const char* FlyingVehicle::sJetSequence[FlyingVehicle::JetAnimCount] =
- {
- "activateBack",
- "maintainBack",
- "activateBot",
- "maintainBot",
- };
- const char* FlyingVehicleData::sJetNode[FlyingVehicleData::MaxJetNodes] =
- {
- "JetNozzle0", // Thrust Forward
- "JetNozzle1",
- "JetNozzleX", // Thrust Backward
- "JetNozzleY",
- "JetNozzle2", // Thrust Downward
- "JetNozzle3",
- "contrail0", // Trail
- "contrail1",
- "contrail2",
- "contrail3",
- };
- // Convert thrust direction into nodes & emitters
- FlyingVehicle::JetActivation FlyingVehicle::sJetActivation[NumThrustDirections] = {
- { FlyingVehicleData::ForwardJetNode, FlyingVehicleData::ForwardJetEmitter },
- { FlyingVehicleData::BackwardJetNode, FlyingVehicleData::BackwardJetEmitter },
- { FlyingVehicleData::DownwardJetNode, FlyingVehicleData::DownwardJetEmitter },
- };
- //----------------------------------------------------------------------------
- IMPLEMENT_CO_DATABLOCK_V1(FlyingVehicleData);
- ConsoleDocClass( FlyingVehicleData,
- "@brief Defines the properties of a FlyingVehicle.\n\n"
- "@ingroup Vehicles\n"
- );
- FlyingVehicleData::FlyingVehicleData()
- {
- maneuveringForce = 0;
- horizontalSurfaceForce = 0;
- verticalSurfaceForce = 0;
- autoInputDamping = 1;
- steeringForce = 1;
- steeringRollForce = 1;
- rollForce = 1;
- autoAngularForce = 0;
- rotationalDrag = 0;
- autoLinearForce = 0;
- maxAutoSpeed = 0;
- hoverHeight = 2;
- createHoverHeight = 2;
- maxSteeringAngle = M_PI_F;
- minTrailSpeed = 1;
- maxSpeed = 100;
- for (S32 k = 0; k < MaxJetNodes; k++)
- jetNode[k] = -1;
- for (S32 j = 0; j < MaxJetEmitters; j++)
- jetEmitter[j] = 0;
- for (S32 i = 0; i < MaxSounds; i++)
- INIT_SOUNDASSET_ARRAY(FlyingSounds, i);
- vertThrustMultiple = 1.0;
- }
- bool FlyingVehicleData::preload(bool server, String &errorStr)
- {
- if (!Parent::preload(server, errorStr))
- return false;
- TSShapeInstance* si = new TSShapeInstance(mShape, false);
- // Resolve objects transmitted from server
- if (!server) {
- for (S32 i = 0; i < MaxSounds; i++)
- {
- if (!isFlyingSoundsValid(i))
- {
- //return false; -TODO: trigger asset download
- }
- }
- for (S32 j = 0; j < MaxJetEmitters; j++)
- if (jetEmitter[j])
- Sim::findObject(SimObjectId((uintptr_t)jetEmitter[j]),jetEmitter[j]);
- }
- // Extract collision planes from shape collision detail level
- if (collisionDetails[0] != -1)
- {
- MatrixF imat(1);
- PlaneExtractorPolyList polyList;
- polyList.mPlaneList = &rigidBody.mPlaneList;
- polyList.setTransform(&imat, Point3F(1,1,1));
- si->animate(collisionDetails[0]);
- si->buildPolyList(&polyList,collisionDetails[0]);
- }
- // Resolve jet nodes
- for (S32 j = 0; j < MaxJetNodes; j++)
- jetNode[j] = mShape->findNode(sJetNode[j]);
- //
- maxSpeed = maneuveringForce / minDrag;
- delete si;
- return true;
- }
- void FlyingVehicleData::initPersistFields()
- {
- docsURL;
- Parent::initPersistFields();
- addGroup("Physics");
- addFieldV( "rollForce", TypeRangedF32, Offset(rollForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "@brief Damping torque against rolling maneuvers (rotation about the y-axis), "
- "proportional to linear velocity.\n\n"
- "Acts to adjust roll to a stable position over time as the vehicle moves." );
- addFieldV( "rotationalDrag", TypeRangedF32, Offset(rotationalDrag, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "Rotational drag factor (slows vehicle rotation speed in all axes)." );
- addFieldV( "horizontalSurfaceForce", TypeRangedF32, Offset(horizontalSurfaceForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "@brief Damping force in the opposite direction to sideways velocity.\n\n"
- "Provides \"bite\" into the wind for climbing/diving and turning)." );
- addFieldV( "hoverHeight", TypeRangedF32, Offset(hoverHeight, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "The vehicle's height off the ground when at rest." );
- addFieldV( "createHoverHeight", TypeRangedF32, Offset(createHoverHeight, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "@brief The vehicle's height off the ground when useCreateHeight is active.\n\n"
- "This can help avoid problems with spawning the vehicle." );
- endGroup("Physics");
- addGroup("Steering");
- addFieldV( "maneuveringForce", TypeRangedF32, Offset(maneuveringForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "@brief Maximum X and Y (horizontal plane) maneuvering force.\n\n"
- "The actual force applied depends on the current thrust." );
- addFieldV( "verticalSurfaceForce", TypeRangedF32, Offset(verticalSurfaceForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "@brief Damping force in the opposite direction to vertical velocity.\n\n"
- "Controls side slip; lower numbers give more slide." );
- addFieldV( "vertThrustMultiple", TypeRangedF32, Offset(vertThrustMultiple, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "Multiplier applied to the jetForce (defined in VehicleData) when thrusting vertically." );
- addFieldV( "steeringForce", TypeRangedF32, Offset(steeringForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "@brief Maximum X and Z (sideways and vertical) steering force.\n\n"
- "The actual force applied depends on the current steering input." );
- addFieldV( "steeringRollForce", TypeRangedF32, Offset(steeringRollForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "Roll force induced by sideways steering input value (controls how much "
- "the vehicle rolls when turning)." );
- endGroup("Steering");
- addGroup("AutoCorrection");
- addFieldV( "maxAutoSpeed", TypeRangedF32, Offset(maxAutoSpeed, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "Maximum speed for automatic vehicle control assistance - vehicles "
- "travelling at speeds above this value do not get control assitance." );
- addFieldV( "autoInputDamping", TypeRangedF32, Offset(autoInputDamping, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "@brief Scale factor applied to steering input if speed is less than "
- "maxAutoSpeed to.improve handling at very low speeds.\n\n"
- "Smaller values make steering less sensitive." );
- addFieldV( "autoLinearForce", TypeRangedF32, Offset(autoLinearForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "@brief Corrective force applied to slow the vehicle when moving at less than "
- "maxAutoSpeed.\n\n"
- "The force is inversely proportional to vehicle speed." );
- addFieldV( "autoAngularForce", TypeRangedF32, Offset(autoAngularForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "@brief Corrective torque applied to level out the vehicle when moving at less "
- "than maxAutoSpeed.\n\n"
- "The torque is inversely proportional to vehicle speed." );
- endGroup("AutoCorrection");
- addGroup("Particle Effects");
- addField( "forwardJetEmitter",TYPEID< ParticleEmitterData >(), Offset(jetEmitter[ForwardJetEmitter], FlyingVehicleData),
- "@brief Emitter to generate particles for forward jet thrust.\n\n"
- "Forward jet thrust particles are emitted from model nodes JetNozzle0 "
- "and JetNozzle1." );
- addField( "backwardJetEmitter",TYPEID< ParticleEmitterData >(), Offset(jetEmitter[BackwardJetEmitter], FlyingVehicleData),
- "@brief Emitter to generate particles for backward jet thrust.\n\n"
- "Backward jet thrust particles are emitted from model nodes JetNozzleX "
- "and JetNozzleY." );
- addField( "downJetEmitter",TYPEID< ParticleEmitterData >(), Offset(jetEmitter[DownwardJetEmitter], FlyingVehicleData),
- "@brief Emitter to generate particles for downward jet thrust.\n\n"
- "Downward jet thrust particles are emitted from model nodes JetNozzle2 "
- "and JetNozzle3." );
- addField( "trailEmitter",TYPEID< ParticleEmitterData >(), Offset(jetEmitter[TrailEmitter], FlyingVehicleData),
- "Emitter to generate contrail particles from model nodes contrail0 - contrail3." );
- addFieldV( "minTrailSpeed", TypeRangedF32, Offset(minTrailSpeed, FlyingVehicleData), &CommonValidators::PositiveFloat,
- "Minimum speed at which to start generating contrail particles." );
- endGroup("Particle Effects");
- addGroup("Sounds");
- INITPERSISTFIELD_SOUNDASSET_ENUMED(FlyingSounds, engineSounds, Sounds::MaxSounds, FlyingVehicleData, "EngineSounds.");
- endGroup("Sounds");
- }
- void FlyingVehicleData::packData(BitStream* stream)
- {
- Parent::packData(stream);
- for (S32 i = 0; i < MaxSounds; i++)
- {
- PACKDATA_SOUNDASSET_ARRAY(FlyingSounds, i);
- }
- for (S32 j = 0; j < MaxJetEmitters; j++)
- {
- if (stream->writeFlag(jetEmitter[j]))
- {
- SimObjectId writtenId = mPacked ? SimObjectId((uintptr_t)jetEmitter[j]) : jetEmitter[j]->getId();
- stream->writeRangedU32(writtenId, DataBlockObjectIdFirst,DataBlockObjectIdLast);
- }
- }
- stream->write(maneuveringForce);
- stream->write(horizontalSurfaceForce);
- stream->write(verticalSurfaceForce);
- stream->write(autoInputDamping);
- stream->write(steeringForce);
- stream->write(steeringRollForce);
- stream->write(rollForce);
- stream->write(autoAngularForce);
- stream->write(rotationalDrag);
- stream->write(autoLinearForce);
- stream->write(maxAutoSpeed);
- stream->write(hoverHeight);
- stream->write(createHoverHeight);
- stream->write(minTrailSpeed);
- stream->write(vertThrustMultiple);
- }
- void FlyingVehicleData::unpackData(BitStream* stream)
- {
- Parent::unpackData(stream);
- for (S32 i = 0; i < MaxSounds; i++)
- {
- UNPACKDATA_SOUNDASSET_ARRAY(FlyingSounds, i);
- }
- for (S32 j = 0; j < MaxJetEmitters; j++) {
- jetEmitter[j] = NULL;
- if (stream->readFlag())
- jetEmitter[j] = (ParticleEmitterData*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst,
- DataBlockObjectIdLast);
- }
- stream->read(&maneuveringForce);
- stream->read(&horizontalSurfaceForce);
- stream->read(&verticalSurfaceForce);
- stream->read(&autoInputDamping);
- stream->read(&steeringForce);
- stream->read(&steeringRollForce);
- stream->read(&rollForce);
- stream->read(&autoAngularForce);
- stream->read(&rotationalDrag);
- stream->read(&autoLinearForce);
- stream->read(&maxAutoSpeed);
- stream->read(&hoverHeight);
- stream->read(&createHoverHeight);
- stream->read(&minTrailSpeed);
- stream->read(&vertThrustMultiple);
- }
- //----------------------------------------------------------------------------
- IMPLEMENT_CO_NETOBJECT_V1(FlyingVehicle);
- ConsoleDocClass( FlyingVehicle,
- "@brief A flying vehicle.\n\n"
- "@ingroup Vehicles\n"
- );
- FlyingVehicle::FlyingVehicle()
- {
- mDataBlock = NULL;
- mSteering.set(0,0);
- mThrottle = 0;
- mJetting = false;
- mJetSound = 0;
- mEngineSound = 0;
- mBackMaintainOn = false;
- mBottomMaintainOn = false;
- createHeightOn = false;
- mCeilingFactor = 1.0f;
- mThrustDirection = FlyingVehicle::ThrustForward;
- for (U32 i=0;i< JetAnimCount;i++)
- mJetSeq[i] = -1;
- for (S32 i = 0; i < JetAnimCount; i++)
- mJetThread[i] = 0;
- }
- FlyingVehicle::~FlyingVehicle()
- {
- }
- //----------------------------------------------------------------------------
- bool FlyingVehicle::onAdd()
- {
- if(!Parent::onAdd())
- return false;
- addToScene();
- return true;
- }
- bool FlyingVehicle::onNewDataBlock(GameBaseData* dptr, bool reload)
- {
- mDataBlock = dynamic_cast<FlyingVehicleData*>(dptr);
- if (!mDataBlock || !Parent::onNewDataBlock(dptr,reload))
- return false;
- // Sounds
- if ( isGhost() )
- {
- // Create the sounds ahead of time. This reduces runtime
- // costs and makes the system easier to understand.
- SFX_DELETE( mJetSound );
- SFX_DELETE( mEngineSound );
- if ( mDataBlock->getFlyingSounds(FlyingVehicleData::EngineSound) )
- mEngineSound = SFX->createSource( mDataBlock->getFlyingSoundsProfile(FlyingVehicleData::EngineSound), &getTransform() );
- if ( mDataBlock->getFlyingSounds(FlyingVehicleData::JetSound))
- mJetSound = SFX->createSource( mDataBlock->getFlyingSoundsProfile(FlyingVehicleData::JetSound), &getTransform() );
- }
- // Jet Sequences
- for (S32 i = 0; i < JetAnimCount; i++) {
- TSShape const* shape = mShapeInstance->getShape();
- mJetSeq[i] = shape->findSequence(sJetSequence[i]);
- if (mJetSeq[i] != -1) {
- if (i == BackActivate || i == BottomActivate) {
- mJetThread[i] = mShapeInstance->addThread();
- mShapeInstance->setSequence(mJetThread[i],mJetSeq[i],0);
- mShapeInstance->setTimeScale(mJetThread[i],0);
- }
- }
- else
- mJetThread[i] = 0;
- }
- scriptOnNewDataBlock();
- return true;
- }
- void FlyingVehicle::onRemove()
- {
- SFX_DELETE( mJetSound );
- SFX_DELETE( mEngineSound );
- removeFromScene();
- Parent::onRemove();
- }
- //----------------------------------------------------------------------------
- void FlyingVehicle::interpolateTick(F32 dt)
- {
- PROFILE_SCOPE(FlyingVehicle_InterpolateTick);
- Parent::interpolateTick(dt);
- updateEngineSound(1);
- updateJet(dt);
- }
- void FlyingVehicle::advanceTime(F32 dt)
- {
- PROFILE_SCOPE(FlyingVehicle_AdvanceTime);
- Parent::advanceTime(dt);
- updateEngineSound(1);
- updateJet(dt);
- }
- //----------------------------------------------------------------------------
- void FlyingVehicle::updateMove(const Move* move)
- {
- PROFILE_SCOPE( FlyingVehicle_UpdateMove );
- Parent::updateMove(move);
- if (move == &NullMove)
- mSteering.set(0,0);
- F32 speed = mRigid.linVelocity.len();
- if (speed < mDataBlock->maxAutoSpeed)
- mSteering *= mDataBlock->autoInputDamping;
- // Check the mission area to get the factor for the flight ceiling
- MissionArea * obj = MissionArea::getServerObject();
- mCeilingFactor = 1.0f;
- 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;
- }
- }
- }
- mThrust.x = move->x;
- mThrust.y = move->y;
- if (mThrust.y != 0.0f)
- if (mThrust.y > 0)
- mThrustDirection = ThrustForward;
- else
- mThrustDirection = ThrustBackward;
- else
- mThrustDirection = ThrustDown;
- if (mCeilingFactor != 1.0f)
- mJetting = false;
- }
- //----------------------------------------------------------------------------
- void FlyingVehicle::updateForces(F32 /*dt*/)
- {
- PROFILE_SCOPE( FlyingVehicle_UpdateForces );
- if (mDisableMove) return;
- 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();
- Point3F force = Point3F(0, 0, mRigid.mass * mNetGravity);
- Point3F torque = Point3F(0, 0, 0);
- // Drag at any speed
- force -= mRigid.linVelocity * mDataBlock->minDrag;
- torque -= mRigid.angMomentum * mDataBlock->rotationalDrag;
- // Auto-stop at low speeds
- if (speed < mDataBlock->maxAutoSpeed) {
- F32 autoScale = 1 - speed / mDataBlock->maxAutoSpeed;
- // Gyroscope
- F32 gf = mDataBlock->autoAngularForce * autoScale;
- torque -= xv * gf * mDot(yv,Point3F(0,0,1));
- // Manuevering jets
- F32 sf = mDataBlock->autoLinearForce * autoScale;
- force -= yv * sf * mDot(yv, mRigid.linVelocity);
- force -= xv * sf * mDot(xv, mRigid.linVelocity);
- }
- // Hovering Jet
- F32 vf = mRigid.mass * -mNetGravity;
- F32 h = getHeight();
- if (h <= 1) {
- F32 seperationForce = vf * (1.0 - h);
- if (h > 0.5) {
- vf -= seperationForce * mDataBlock->drag;
- } else {
- if (h < 0.0)
- {
- Point3F displacePos = getPosition();
- displacePos.z += mDataBlock->hoverHeight * (-h * 2);
- mRigid.linPosition = displacePos;
- }
- vf += seperationForce;
- }
- }
- force.z += vf;
- // Damping "surfaces"
- force -= xv * mDot(xv,mRigid.linVelocity) * mDataBlock->horizontalSurfaceForce;
- force -= zv * mDot(zv,mRigid.linVelocity) * mDataBlock->verticalSurfaceForce;
- // Turbo Jet
- if (mJetting) {
- if (mThrustDirection == ThrustForward)
- force += yv * mDataBlock->jetForce * mCeilingFactor;
- else if (mThrustDirection == ThrustBackward)
- force -= yv * mDataBlock->jetForce * mCeilingFactor;
- else
- force += zv * mDataBlock->jetForce * mDataBlock->vertThrustMultiple * mCeilingFactor;
- }
- // Maneuvering jets
- force += yv * (mThrust.y * mDataBlock->maneuveringForce * mCeilingFactor);
- force += xv * (mThrust.x * mDataBlock->maneuveringForce * mCeilingFactor);
- // Steering
- Point2F steering;
- steering.x = mSteering.x / mDataBlock->maxSteeringAngle;
- steering.x *= mFabs(steering.x);
- steering.y = mSteering.y / mDataBlock->maxSteeringAngle;
- steering.y *= mFabs(steering.y);
- torque -= xv * steering.y * mDataBlock->steeringForce;
- torque -= zv * steering.x * mDataBlock->steeringForce;
- // Roll
- torque += yv * steering.x * mDataBlock->steeringRollForce;
- F32 ar = mDataBlock->autoAngularForce * mDot(xv,Point3F(0,0,1));
- ar -= mDataBlock->rollForce * mDot(xv, mRigid.linVelocity);
- torque += yv * ar;
- // Add in force from physical zones...
- force += mAppliedForce;
- force -= mRigid.linVelocity * mDrag;
- //
- mRigid.force = force;
- mRigid.torque = torque;
- }
- //----------------------------------------------------------------------------
- F32 FlyingVehicle::getHeight()
- {
- Point3F sp,ep;
- RayInfo collision;
- F32 height = ((createHeightOn) ? mDataBlock->createHoverHeight : mDataBlock->hoverHeight) + mDataBlock->collisionTol*2;
- F32 r = 3 * height;
- getTransform().getColumn(3, &sp);
- ep.x = sp.x;
- ep.y = sp.y;
- ep.z = sp.z - r;
- disableCollision();
- if( !mContainer->castRay(sp, ep, sClientCollisionMask, &collision) == true )
- collision.t = 1;
- enableCollision();
- return (r * collision.t - height) / r;
- }
- //----------------------------------------------------------------------------
- U32 FlyingVehicle::getCollisionMask()
- {
- if (isServerObject())
- return sServerCollisionMask;
- else
- return sClientCollisionMask;
- }
- //----------------------------------------------------------------------------
- void FlyingVehicle::updateEngineSound(F32 level)
- {
- if ( !mEngineSound )
- return;
- if ( !mEngineSound->isPlaying() )
- mEngineSound->play();
- mEngineSound->setTransform( getTransform() );
- mEngineSound->setVelocity( getVelocity() );
- mEngineSound->setPitch( level );
- }
- void FlyingVehicle::updateJet(F32 dt)
- {
- // Thrust Animation threads
- // Back
- if (mJetSeq[BackActivate] >=0 ) {
- if(!mBackMaintainOn || mThrustDirection != ThrustForward) {
- if(mBackMaintainOn) {
- mShapeInstance->setPos(mJetThread[BackActivate], 1);
- mShapeInstance->destroyThread(mJetThread[BackMaintain]);
- mBackMaintainOn = false;
- }
- mShapeInstance->setTimeScale(mJetThread[BackActivate],
- (mThrustDirection == ThrustForward)? 1.0f : -1.0f);
- mShapeInstance->advanceTime(dt,mJetThread[BackActivate]);
- }
- if(mJetSeq[BackMaintain] >= 0 && !mBackMaintainOn &&
- mShapeInstance->getPos(mJetThread[BackActivate]) >= 1.0) {
- mShapeInstance->setPos(mJetThread[BackActivate], 0);
- mShapeInstance->setTimeScale(mJetThread[BackActivate], 0);
- mJetThread[BackMaintain] = mShapeInstance->addThread();
- mShapeInstance->setSequence(mJetThread[BackMaintain],mJetSeq[BackMaintain],0);
- mShapeInstance->setTimeScale(mJetThread[BackMaintain],1);
- mBackMaintainOn = true;
- }
- if(mBackMaintainOn)
- mShapeInstance->advanceTime(dt,mJetThread[BackMaintain]);
- }
- // Thrust Animation threads
- // Bottom
- if (mJetSeq[BottomActivate] >=0 ) {
- if(!mBottomMaintainOn || mThrustDirection != ThrustDown || !mJetting) {
- if(mBottomMaintainOn) {
- mShapeInstance->setPos(mJetThread[BottomActivate], 1);
- mShapeInstance->destroyThread(mJetThread[BottomMaintain]);
- mBottomMaintainOn = false;
- }
- mShapeInstance->setTimeScale(mJetThread[BottomActivate],
- (mThrustDirection == ThrustDown && mJetting)? 1.0f : -1.0f);
- mShapeInstance->advanceTime(dt,mJetThread[BottomActivate]);
- }
- if(mJetSeq[BottomMaintain] >= 0 && !mBottomMaintainOn &&
- mShapeInstance->getPos(mJetThread[BottomActivate]) >= 1.0) {
- mShapeInstance->setPos(mJetThread[BottomActivate], 0);
- mShapeInstance->setTimeScale(mJetThread[BottomActivate], 0);
- mJetThread[BottomMaintain] = mShapeInstance->addThread();
- mShapeInstance->setSequence(mJetThread[BottomMaintain],mJetSeq[BottomMaintain],0);
- mShapeInstance->setTimeScale(mJetThread[BottomMaintain],1);
- mBottomMaintainOn = true;
- }
- if(mBottomMaintainOn)
- mShapeInstance->advanceTime(dt,mJetThread[BottomMaintain]);
- }
- // Jet particles
- for (S32 j = 0; j < NumThrustDirections; j++) {
- JetActivation& jet = sJetActivation[j];
- updateEmitter(mJetting && j == mThrustDirection,dt,mDataBlock->jetEmitter[jet.emitter],
- jet.node,FlyingVehicleData::MaxDirectionJets);
- }
- // Trail jets
- Point3F yv;
- mObjToWorld.getColumn(1,&yv);
- F32 speed = mFabs(mDot(yv,mRigid.linVelocity));
- F32 trail = 0;
- if (speed > mDataBlock->minTrailSpeed) {
- trail = dt;
- if (speed < mDataBlock->maxSpeed)
- trail *= (speed - mDataBlock->minTrailSpeed) / mDataBlock->maxSpeed;
- }
- updateEmitter(trail,trail,mDataBlock->jetEmitter[FlyingVehicleData::TrailEmitter],
- FlyingVehicleData::TrailNode,FlyingVehicleData::MaxTrails);
- // Allocate/Deallocate voice on demand.
- if ( !mJetSound )
- return;
- if ( !mJetting )
- mJetSound->stop();
- else
- {
- if ( !mJetSound->isPlaying() )
- mJetSound->play();
- mJetSound->setTransform( getTransform() );
- mJetSound->setVelocity( getVelocity() );
- }
- }
- //----------------------------------------------------------------------------
- void FlyingVehicle::updateEmitter(bool active,F32 dt,ParticleEmitterData *emitter,S32 idx,S32 count)
- {
- if (!emitter)
- return;
- for (S32 j = idx; j < idx + count; j++)
- if (active) {
- if (mDataBlock->jetNode[j] != -1) {
- if (!bool(mJetEmitter[j])) {
- mJetEmitter[j] = new ParticleEmitter;
- mJetEmitter[j]->onNewDataBlock(emitter,false);
- mJetEmitter[j]->registerObject();
- }
- MatrixF mat;
- Point3F pos,axis;
- mat.mul(getRenderTransform(),
- mShapeInstance->mNodeTransforms[mDataBlock->jetNode[j]]);
- mat.getColumn(1,&axis);
- mat.getColumn(3,&pos);
- mJetEmitter[j]->emitParticles(pos,true,axis,getVelocity(),(U32)(dt * 1000));
- }
- }
- else {
- for (S32 k = idx; k < idx + count; k++)
- if (bool(mJetEmitter[k])) {
- mJetEmitter[k]->deleteWhenEmpty();
- mJetEmitter[k] = 0;
- }
- }
- }
- //----------------------------------------------------------------------------
- void FlyingVehicle::writePacketData(GameConnection *connection, BitStream *stream)
- {
- Parent::writePacketData(connection, stream);
- }
- void FlyingVehicle::readPacketData(GameConnection *connection, BitStream *stream)
- {
- Parent::readPacketData(connection, stream);
- setPosition(mRigid.linPosition,mRigid.angPosition);
- mDelta.pos = mRigid.linPosition;
- mDelta.rot[1] = mRigid.angPosition;
- }
- U32 FlyingVehicle::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
- {
- U32 retMask = Parent::packUpdate(con, mask, stream);
- // The rest of the data is part of the control object packet update.
- // If we're controlled by this client, we don't need to send it.
- if(stream->writeFlag(getControllingClient() == con && !(mask & InitialUpdateMask)))
- return retMask;
- stream->writeFlag(createHeightOn);
- stream->writeInt(mThrustDirection,NumThrustBits);
- return retMask;
- }
- void FlyingVehicle::unpackUpdate(NetConnection *con, BitStream *stream)
- {
- Parent::unpackUpdate(con,stream);
- if(stream->readFlag())
- return;
- createHeightOn = stream->readFlag();
- mThrustDirection = ThrustDirection(stream->readInt(NumThrustBits));
- }
- void FlyingVehicle::initPersistFields()
- {
- docsURL;
- Parent::initPersistFields();
- }
- DefineEngineMethod( FlyingVehicle, useCreateHeight, void, ( bool enabled ),,
- "@brief Set whether the vehicle should temporarily use the createHoverHeight "
- "specified in the datablock.\n\nThis can help avoid problems with spawning.\n"
- "@param enabled true to use the datablock createHoverHeight, false otherwise\n" )
- {
- object->useCreateHeight( enabled );
- }
- void FlyingVehicle::useCreateHeight(bool val)
- {
- createHeightOn = val;
- setMaskBits(HoverHeight);
- }
|