mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-13 15:44:36 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
804
Engine/source/T3D/vehicles/flyingVehicle.cpp
Normal file
804
Engine/source/T3D/vehicles/flyingVehicle.cpp
Normal file
|
|
@ -0,0 +1,804 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 | InteriorObjectType |
|
||||
WaterObjectType | PlayerObjectType |
|
||||
StaticShapeObjectType | VehicleObjectType |
|
||||
VehicleBlockerObjectType );
|
||||
static U32 sServerCollisionMask = sCollisionMoveMask; // ItemObjectType
|
||||
static U32 sClientCollisionMask = sCollisionMoveMask;
|
||||
|
||||
static F32 sFlyingVehicleGravity = -20.0f;
|
||||
|
||||
//
|
||||
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++)
|
||||
sound[i] = 0;
|
||||
|
||||
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 (sound[i])
|
||||
Sim::findObject(SimObjectId(sound[i]),sound[i]);
|
||||
|
||||
for (S32 j = 0; j < MaxJetEmitters; j++)
|
||||
if (jetEmitter[j])
|
||||
Sim::findObject(SimObjectId(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()
|
||||
{
|
||||
addField( "jetSound", TYPEID< SFXProfile >(), Offset(sound[JetSound], FlyingVehicleData),
|
||||
"Looping sound to play while the vehicle is jetting." );
|
||||
addField( "engineSound", TYPEID< SFXProfile >(), Offset(sound[EngineSound], FlyingVehicleData),
|
||||
"Looping engine sound." );
|
||||
|
||||
addField( "maneuveringForce", TypeF32, Offset(maneuveringForce, FlyingVehicleData),
|
||||
"@brief Maximum X and Y (horizontal plane) maneuvering force.\n\n"
|
||||
"The actual force applied depends on the current thrust." );
|
||||
addField( "horizontalSurfaceForce", TypeF32, Offset(horizontalSurfaceForce, FlyingVehicleData),
|
||||
"@brief Damping force in the opposite direction to sideways velocity.\n\n"
|
||||
"Provides \"bite\" into the wind for climbing/diving and turning)." );
|
||||
addField( "verticalSurfaceForce", TypeF32, Offset(verticalSurfaceForce, FlyingVehicleData),
|
||||
"@brief Damping force in the opposite direction to vertical velocity.\n\n"
|
||||
"Controls side slip; lower numbers give more slide." );
|
||||
addField( "vertThrustMultiple", TypeF32, Offset(vertThrustMultiple, FlyingVehicleData),
|
||||
"Multiplier applied to the jetForce (defined in VehicleData) when thrusting vertically." );
|
||||
addField( "steeringForce", TypeF32, Offset(steeringForce, FlyingVehicleData),
|
||||
"@brief Maximum X and Z (sideways and vertical) steering force.\n\n"
|
||||
"The actual force applied depends on the current steering input." );
|
||||
addField( "steeringRollForce", TypeF32, Offset(steeringRollForce, FlyingVehicleData),
|
||||
"Roll force induced by sideways steering input value (controls how much "
|
||||
"the vehicle rolls when turning)." );
|
||||
addField( "rollForce", TypeF32, Offset(rollForce, FlyingVehicleData),
|
||||
"@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." );
|
||||
addField( "rotationalDrag", TypeF32, Offset(rotationalDrag, FlyingVehicleData),
|
||||
"Rotational drag factor (slows vehicle rotation speed in all axes)." );
|
||||
|
||||
addField( "maxAutoSpeed", TypeF32, Offset(maxAutoSpeed, FlyingVehicleData),
|
||||
"Maximum speed for automatic vehicle control assistance - vehicles "
|
||||
"travelling at speeds above this value do not get control assitance." );
|
||||
addField( "autoInputDamping", TypeF32, Offset(autoInputDamping, FlyingVehicleData),
|
||||
"@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." );
|
||||
addField( "autoLinearForce", TypeF32, Offset(autoLinearForce, FlyingVehicleData),
|
||||
"@brief Corrective force applied to slow the vehicle when moving at less than "
|
||||
"maxAutoSpeed.\n\n"
|
||||
"The force is inversely proportional to vehicle speed." );
|
||||
addField( "autoAngularForce", TypeF32, Offset(autoAngularForce, FlyingVehicleData),
|
||||
"@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." );
|
||||
|
||||
addField( "hoverHeight", TypeF32, Offset(hoverHeight, FlyingVehicleData),
|
||||
"The vehicle's height off the ground when at rest." );
|
||||
addField( "createHoverHeight", TypeF32, Offset(createHoverHeight, FlyingVehicleData),
|
||||
"@brief The vehicle's height off the ground when useCreateHeight is active.\n\n"
|
||||
"This can help avoid problems with spawning the vehicle." );
|
||||
|
||||
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." );
|
||||
addField( "minTrailSpeed", TypeF32, Offset(minTrailSpeed, FlyingVehicleData),
|
||||
"Minimum speed at which to start generating contrail particles." );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void FlyingVehicleData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
for (S32 i = 0; i < MaxSounds; i++)
|
||||
{
|
||||
if (stream->writeFlag(sound[i]))
|
||||
{
|
||||
SimObjectId writtenId = packed ? SimObjectId(sound[i]) : sound[i]->getId();
|
||||
stream->writeRangedU32(writtenId, DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
}
|
||||
}
|
||||
|
||||
for (S32 j = 0; j < MaxJetEmitters; j++)
|
||||
{
|
||||
if (stream->writeFlag(jetEmitter[j]))
|
||||
{
|
||||
SimObjectId writtenId = packed ? SimObjectId(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++) {
|
||||
sound[i] = NULL;
|
||||
if (stream->readFlag())
|
||||
sound[i] = (SFXProfile*)stream->readRangedU32(DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
}
|
||||
|
||||
for (S32 j = 0; j < MaxJetEmitters; j++) {
|
||||
jetEmitter[j] = NULL;
|
||||
if (stream->readFlag())
|
||||
jetEmitter[j] = (ParticleEmitterData*)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()
|
||||
{
|
||||
mSteering.set(0,0);
|
||||
mThrottle = 0;
|
||||
mJetting = false;
|
||||
|
||||
mJetSound = 0;
|
||||
mEngineSound = 0;
|
||||
|
||||
mBackMaintainOn = false;
|
||||
mBottomMaintainOn = false;
|
||||
createHeightOn = false;
|
||||
|
||||
for (S32 i = 0; i < JetAnimCount; i++)
|
||||
mJetThread[i] = 0;
|
||||
}
|
||||
|
||||
FlyingVehicle::~FlyingVehicle()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool FlyingVehicle::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
addToScene();
|
||||
|
||||
if (isServerObject())
|
||||
scriptOnAdd();
|
||||
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->sound[FlyingVehicleData::EngineSound] )
|
||||
mEngineSound = SFX->createSource( mDataBlock->sound[FlyingVehicleData::EngineSound], &getTransform() );
|
||||
|
||||
if ( mDataBlock->sound[FlyingVehicleData::JetSound] )
|
||||
mJetSound = SFX->createSource( mDataBlock->sound[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 );
|
||||
|
||||
scriptOnRemove();
|
||||
removeFromScene();
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void FlyingVehicle::advanceTime(F32 dt)
|
||||
{
|
||||
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 );
|
||||
|
||||
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, sFlyingVehicleGravity * mRigid.mass * mGravityMod);
|
||||
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 = -sFlyingVehicleGravity * mRigid.mass * mGravityMod;
|
||||
F32 h = getHeight();
|
||||
if (h <= 1) {
|
||||
if (h > 0) {
|
||||
vf -= vf * h * 0.1;
|
||||
} else {
|
||||
vf += mDataBlock->jetForce * -h;
|
||||
}
|
||||
}
|
||||
force += zv * 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;
|
||||
|
||||
// Container buoyancy & drag
|
||||
force -= Point3F(0, 0, 1) * (mBuoyancy * sFlyingVehicleGravity * mRigid.mass * mGravityMod);
|
||||
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;
|
||||
F32 r = 10 + 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) / 10;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
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 j = idx; j < idx + count; j++)
|
||||
if (bool(mJetEmitter[j])) {
|
||||
mJetEmitter[j]->deleteWhenEmpty();
|
||||
mJetEmitter[j] = 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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
200
Engine/source/T3D/vehicles/flyingVehicle.h
Normal file
200
Engine/source/T3D/vehicles/flyingVehicle.h
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _FLYINGVEHICLE_H_
|
||||
#define _FLYINGVEHICLE_H_
|
||||
|
||||
#ifndef _VEHICLE_H_
|
||||
#include "T3D/vehicles/vehicle.h"
|
||||
#endif
|
||||
|
||||
#ifndef _CLIPPEDPOLYLIST_H_
|
||||
#include "collision/clippedPolyList.h"
|
||||
#endif
|
||||
|
||||
class ParticleEmitter;
|
||||
class ParticleEmitterData;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
struct FlyingVehicleData: public VehicleData {
|
||||
typedef VehicleData Parent;
|
||||
|
||||
enum Sounds {
|
||||
JetSound,
|
||||
EngineSound,
|
||||
MaxSounds,
|
||||
};
|
||||
SFXProfile* sound[MaxSounds];
|
||||
|
||||
enum Jets {
|
||||
// These enums index into a static name list.
|
||||
ForwardJetEmitter, // Thrust forward
|
||||
BackwardJetEmitter, // Thrust backward
|
||||
DownwardJetEmitter, // Thrust down
|
||||
TrailEmitter, // Contrail
|
||||
MaxJetEmitters,
|
||||
};
|
||||
ParticleEmitterData* jetEmitter[MaxJetEmitters];
|
||||
F32 minTrailSpeed;
|
||||
|
||||
//
|
||||
F32 maneuveringForce;
|
||||
F32 horizontalSurfaceForce;
|
||||
F32 verticalSurfaceForce;
|
||||
F32 autoInputDamping;
|
||||
F32 steeringForce;
|
||||
F32 steeringRollForce;
|
||||
F32 rollForce;
|
||||
F32 autoAngularForce;
|
||||
F32 rotationalDrag;
|
||||
F32 maxAutoSpeed;
|
||||
F32 autoLinearForce;
|
||||
F32 hoverHeight;
|
||||
F32 createHoverHeight;
|
||||
|
||||
F32 vertThrustMultiple;
|
||||
|
||||
// Initialized in preload
|
||||
ClippedPolyList rigidBody;
|
||||
S32 surfaceCount;
|
||||
F32 maxSpeed;
|
||||
|
||||
enum JetNodes {
|
||||
// These enums index into a static name list.
|
||||
ForwardJetNode,
|
||||
ForwardJetNode1,
|
||||
BackwardJetNode,
|
||||
BackwardJetNode1,
|
||||
DownwardJetNode,
|
||||
DownwardJetNode1,
|
||||
//
|
||||
TrailNode,
|
||||
TrailNode1,
|
||||
TrailNode2,
|
||||
TrailNode3,
|
||||
//
|
||||
MaxJetNodes,
|
||||
MaxDirectionJets = 2,
|
||||
ThrustJetStart = ForwardJetNode,
|
||||
NumThrustJets = TrailNode,
|
||||
MaxTrails = 4,
|
||||
};
|
||||
static const char *sJetNode[MaxJetNodes];
|
||||
S32 jetNode[MaxJetNodes];
|
||||
|
||||
//
|
||||
FlyingVehicleData();
|
||||
DECLARE_CONOBJECT(FlyingVehicleData);
|
||||
static void initPersistFields();
|
||||
bool preload(bool server, String &errorStr);
|
||||
void packData(BitStream* stream);
|
||||
void unpackData(BitStream* stream);
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class FlyingVehicle: public Vehicle
|
||||
{
|
||||
typedef Vehicle Parent;
|
||||
|
||||
FlyingVehicleData* mDataBlock;
|
||||
|
||||
SFXSource* mJetSound;
|
||||
SFXSource* mEngineSound;
|
||||
|
||||
enum NetMaskBits {
|
||||
InitMask = BIT(0),
|
||||
HoverHeight = BIT(1)
|
||||
};
|
||||
bool createHeightOn;
|
||||
F32 mCeilingFactor;
|
||||
|
||||
enum ThrustDirection {
|
||||
// Enums index into sJetActivationTable
|
||||
ThrustForward,
|
||||
ThrustBackward,
|
||||
ThrustDown,
|
||||
NumThrustDirections,
|
||||
NumThrustBits = 3
|
||||
};
|
||||
Point2F mThrust;
|
||||
ThrustDirection mThrustDirection;
|
||||
|
||||
// Jet Threads
|
||||
enum Jets {
|
||||
// These enums index into a static name list.
|
||||
BackActivate,
|
||||
BackMaintain,
|
||||
BottomActivate,
|
||||
BottomMaintain,
|
||||
JetAnimCount
|
||||
};
|
||||
static const char* sJetSequence[FlyingVehicle::JetAnimCount];
|
||||
TSThread* mJetThread[JetAnimCount];
|
||||
S32 mJetSeq[JetAnimCount];
|
||||
bool mBackMaintainOn;
|
||||
bool mBottomMaintainOn;
|
||||
// Jet Particles
|
||||
struct JetActivation {
|
||||
// Convert thrust direction into nodes & emitters
|
||||
S32 node;
|
||||
S32 emitter;
|
||||
};
|
||||
static JetActivation sJetActivation[NumThrustDirections];
|
||||
SimObjectPtr<ParticleEmitter> mJetEmitter[FlyingVehicleData::MaxJetNodes];
|
||||
|
||||
//
|
||||
bool onNewDataBlock(GameBaseData* dptr,bool reload);
|
||||
void updateMove(const Move *move);
|
||||
void updateForces(F32);
|
||||
// bool collideBody(const MatrixF& mat,Collision* info);
|
||||
F32 getHeight();
|
||||
|
||||
// Client sounds & particles
|
||||
void updateJet(F32 dt);
|
||||
void updateEngineSound(F32 level);
|
||||
void updateEmitter(bool active,F32 dt,ParticleEmitterData *emitter,S32 idx,S32 count);
|
||||
|
||||
U32 getCollisionMask();
|
||||
public:
|
||||
DECLARE_CONOBJECT(FlyingVehicle);
|
||||
static void initPersistFields();
|
||||
|
||||
FlyingVehicle();
|
||||
~FlyingVehicle();
|
||||
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void advanceTime(F32 dt);
|
||||
|
||||
void writePacketData(GameConnection *conn, BitStream *stream);
|
||||
void readPacketData(GameConnection *conn, BitStream *stream);
|
||||
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
void useCreateHeight(bool val);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
212
Engine/source/T3D/vehicles/guiSpeedometer.cpp
Normal file
212
Engine/source/T3D/vehicles/guiSpeedometer.cpp
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "gui/controls/guiBitmapCtrl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "T3D/gameBase/gameConnection.h"
|
||||
#include "T3D/vehicles/vehicle.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// A Speedometer control.
|
||||
/// This gui displays the speed of the current Vehicle based
|
||||
/// control object. This control only works if a server
|
||||
/// connection exists and its control object is a vehicle. If
|
||||
/// either of these requirements is false, the control is not rendered.
|
||||
class GuiSpeedometerHud : public GuiBitmapCtrl
|
||||
{
|
||||
typedef GuiBitmapCtrl Parent;
|
||||
|
||||
F32 mSpeed; ///< Current speed
|
||||
F32 mMaxSpeed; ///< Max speed at max need pos
|
||||
F32 mMaxAngle; ///< Max pos of needle
|
||||
F32 mMinAngle; ///< Min pos of needle
|
||||
Point2F mCenter; ///< Center of needle rotation
|
||||
ColorF mColor; ///< Needle Color
|
||||
F32 mNeedleLength;
|
||||
F32 mNeedleWidth;
|
||||
F32 mTailLength;
|
||||
|
||||
GFXStateBlockRef mBlendSB;
|
||||
|
||||
public:
|
||||
GuiSpeedometerHud();
|
||||
|
||||
void onRender( Point2I, const RectI &);
|
||||
static void initPersistFields();
|
||||
DECLARE_CONOBJECT( GuiSpeedometerHud );
|
||||
DECLARE_CATEGORY( "Gui Game" );
|
||||
DECLARE_DESCRIPTION( "Displays the speed of the current Vehicle-based control object." );
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CONOBJECT( GuiSpeedometerHud );
|
||||
|
||||
ConsoleDocClass( GuiSpeedometerHud,
|
||||
"@brief Displays the speed of the current Vehicle based control object.\n\n"
|
||||
|
||||
"This control only works if a server connection exists, and its control "
|
||||
"object is a Vehicle derived class. If either of these requirements is false, "
|
||||
"the control is not rendered.<br>"
|
||||
|
||||
"The control renders the speedometer needle as a colored quad, rotated to "
|
||||
"indicate the Vehicle speed as determined by the <i>minAngle</i>, "
|
||||
"<i>maxAngle</i>, and <i>maxSpeed</i> properties. This control is normally "
|
||||
"placed on top of a GuiBitmapCtrl representing the speedometer dial.\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"new GuiSpeedometerHud()\n"
|
||||
"{\n"
|
||||
" maxSpeed = \"100\";\n"
|
||||
" minAngle = \"215\";\n"
|
||||
" maxAngle = \"0\";\n"
|
||||
" color = \"1 0.3 0.3 1\";\n"
|
||||
" center = \"130 123\";\n"
|
||||
" length = \"100\";\n"
|
||||
" width = \"2\";\n"
|
||||
" tail = \"0\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@ingroup GuiContainers"
|
||||
);
|
||||
|
||||
GuiSpeedometerHud::GuiSpeedometerHud()
|
||||
{
|
||||
mSpeed = 0;
|
||||
mMaxSpeed = 100;
|
||||
mMaxAngle = 0;
|
||||
mMinAngle = 200;
|
||||
mCenter.set(0,0);
|
||||
mNeedleWidth = 3;
|
||||
mNeedleLength = 10;
|
||||
mTailLength = 5;
|
||||
mColor.set(1,0,0,1);
|
||||
}
|
||||
|
||||
void GuiSpeedometerHud::initPersistFields()
|
||||
{
|
||||
addGroup("Needle");
|
||||
|
||||
addField("maxSpeed", TypeF32, Offset( mMaxSpeed, GuiSpeedometerHud ),
|
||||
"Maximum Vehicle speed (in Torque units per second) to represent on the "
|
||||
"speedo (Vehicle speeds greater than this are clamped to maxSpeed)." );
|
||||
|
||||
addField("minAngle", TypeF32, Offset( mMinAngle, GuiSpeedometerHud ),
|
||||
"Angle (in radians) of the needle when the Vehicle speed is 0. An angle "
|
||||
"of 0 points right, 90 points up etc)." );
|
||||
|
||||
addField("maxAngle", TypeF32, Offset( mMaxAngle, GuiSpeedometerHud ),
|
||||
"Angle (in radians) of the needle when the Vehicle speed is >= maxSpeed. "
|
||||
"An angle of 0 points right, 90 points up etc)." );
|
||||
|
||||
addField("color", TypeColorF, Offset( mColor, GuiSpeedometerHud ),
|
||||
"Color of the needle" );
|
||||
|
||||
addField("center", TypePoint2F, Offset( mCenter, GuiSpeedometerHud ),
|
||||
"Center of the needle, offset from the GuiSpeedometerHud control top "
|
||||
"left corner" );
|
||||
|
||||
addField("length", TypeF32, Offset( mNeedleLength, GuiSpeedometerHud ),
|
||||
"Length of the needle from center to end" );
|
||||
|
||||
addField("width", TypeF32, Offset( mNeedleWidth, GuiSpeedometerHud ),
|
||||
"Width of the needle" );
|
||||
|
||||
addField("tail", TypeF32, Offset( mTailLength, GuiSpeedometerHud ),
|
||||
"Length of the needle from center to tail" );
|
||||
|
||||
endGroup("Needle");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
Gui onRender method.
|
||||
Renders a health bar with filled background and border.
|
||||
*/
|
||||
void GuiSpeedometerHud::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
// Must have a connection and player control object
|
||||
GameConnection* conn = GameConnection::getConnectionToServer();
|
||||
if (!conn)
|
||||
return;
|
||||
Vehicle* control = dynamic_cast<Vehicle*>(conn->getControlObject());
|
||||
if (!control)
|
||||
return;
|
||||
|
||||
Parent::onRender(offset,updateRect);
|
||||
|
||||
// Use the vehicle's velocity as its speed...
|
||||
mSpeed = control->getVelocity().len();
|
||||
if (mSpeed > mMaxSpeed)
|
||||
mSpeed = mMaxSpeed;
|
||||
|
||||
// Render the needle
|
||||
GFX->pushWorldMatrix();
|
||||
Point2F center = mCenter;
|
||||
if (mIsZero(center.x) && mIsZero(center.y))
|
||||
{
|
||||
center.x = getExtent().x / 2.0f;
|
||||
center.y = getExtent().y / 2.0f;
|
||||
}
|
||||
MatrixF newMat(1);
|
||||
|
||||
newMat.setPosition(Point3F(getLeft() + center.x, getTop() + center.y, 0.0f));
|
||||
|
||||
F32 rotation = mMinAngle + (mMaxAngle - mMinAngle) * (mSpeed / mMaxSpeed);
|
||||
AngAxisF newRot(Point3F(0.0f,0.0f,-1.0f), rotation);
|
||||
|
||||
newRot.setMatrix(&newMat);
|
||||
|
||||
if (mBlendSB.isNull())
|
||||
{
|
||||
GFXStateBlockDesc desc;
|
||||
desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
|
||||
desc.samplersDefined = true;
|
||||
desc.samplers[0].textureColorOp = GFXTOPDisable;
|
||||
mBlendSB = GFX->createStateBlock(desc);
|
||||
}
|
||||
|
||||
GFX->setStateBlock(mBlendSB);
|
||||
|
||||
GFX->setTexture(0, NULL);
|
||||
|
||||
PrimBuild::begin(GFXLineStrip, 5);
|
||||
PrimBuild::color4f(mColor.red, mColor.green, mColor.blue, mColor.alpha);
|
||||
|
||||
PrimBuild::vertex2f(+mNeedleLength,-mNeedleWidth);
|
||||
PrimBuild::vertex2f(+mNeedleLength,+mNeedleWidth);
|
||||
PrimBuild::vertex2f(-mTailLength ,+mNeedleWidth);
|
||||
PrimBuild::vertex2f(-mTailLength ,-mNeedleWidth);
|
||||
|
||||
//// Get back to the start!
|
||||
PrimBuild::vertex2f(+mNeedleLength,-mNeedleWidth);
|
||||
|
||||
PrimBuild::end();
|
||||
}
|
||||
|
||||
976
Engine/source/T3D/vehicles/hoverVehicle.cpp
Normal file
976
Engine/source/T3D/vehicles/hoverVehicle.cpp
Normal file
|
|
@ -0,0 +1,976 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/hoverVehicle.h"
|
||||
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "collision/clippedPolyList.h"
|
||||
#include "collision/planeExtractor.h"
|
||||
#include "T3D/gameBase/moveManager.h"
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "sfx/sfxSystem.h"
|
||||
#include "sfx/sfxProfile.h"
|
||||
#include "sfx/sfxSource.h"
|
||||
#include "T3D/fx/particleEmitter.h"
|
||||
#include "math/mathIO.h"
|
||||
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(HoverVehicleData);
|
||||
IMPLEMENT_CO_NETOBJECT_V1(HoverVehicle);
|
||||
|
||||
ConsoleDocClass( HoverVehicleData,
|
||||
"@brief Defines the properties of a HoverVehicle.\n\n"
|
||||
"@ingroup Vehicles\n"
|
||||
);
|
||||
|
||||
ConsoleDocClass( HoverVehicle,
|
||||
"@brief A hovering vehicle.\n\n"
|
||||
"A hover vehicle is a vehicle that maintains a specific distance between the "
|
||||
"vehicle and the ground at all times; unlike a flying vehicle which is free "
|
||||
"to ascend and descend at will."
|
||||
"The model used for the HoverVehicle has the following requirements:\n"
|
||||
"<dl>"
|
||||
"<dt>Collision mesh</dt><dd>A convex collision mesh at detail size -1.</dd>"
|
||||
"<dt>JetNozzle0-1 nodes</dt><dd>Particle emitter nodes used when thrusting "
|
||||
"forward.</dd>"
|
||||
"<dt>JetNozzle2-3 nodes</dt><dd>Particle emitter nodes used when thrusting "
|
||||
"downward.</dd>"
|
||||
"<dt>JetNozzleX node</dt><dd>Particle emitter node used when thrusting "
|
||||
"backward.</dd>"
|
||||
"<dt>activateBack animation</dt><dd>Non-cyclic animation sequence played "
|
||||
"when the vehicle begins thrusting forwards.</dd>"
|
||||
"<dt>maintainBack animation</dt><dd>Cyclic animation sequence played after "
|
||||
"activateBack when the vehicle continues thrusting forwards.</dd>"
|
||||
"</dl>"
|
||||
"@ingroup Vehicles\n"
|
||||
);
|
||||
|
||||
namespace {
|
||||
|
||||
const U32 sIntergrationsPerTick = 1;
|
||||
const F32 sHoverVehicleGravity = -20;
|
||||
|
||||
const U32 sCollisionMoveMask = (TerrainObjectType | InteriorObjectType |
|
||||
PlayerObjectType | StaticShapeObjectType |
|
||||
VehicleObjectType | VehicleBlockerObjectType);
|
||||
|
||||
const U32 sServerCollisionMask = sCollisionMoveMask; // ItemObjectType
|
||||
const U32 sClientCollisionMask = sCollisionMoveMask;
|
||||
|
||||
void nonFilter(SceneObject* object,void *key)
|
||||
{
|
||||
SceneContainer::CallbackInfo* info = reinterpret_cast<SceneContainer::CallbackInfo*>(key);
|
||||
object->buildPolyList(info->context,info->polyList,info->boundingBox,info->boundingSphere);
|
||||
}
|
||||
|
||||
} // namespace {}
|
||||
|
||||
const char* HoverVehicle::sJetSequence[HoverVehicle::JetAnimCount] =
|
||||
{
|
||||
"activateBack",
|
||||
"maintainBack",
|
||||
};
|
||||
|
||||
const char* HoverVehicleData::sJetNode[HoverVehicleData::MaxJetNodes] =
|
||||
{
|
||||
"JetNozzle0", // Thrust Forward
|
||||
"JetNozzle1",
|
||||
"JetNozzleX", // Thrust Backward
|
||||
"JetNozzleX",
|
||||
"JetNozzle2", // Thrust Downward
|
||||
"JetNozzle3",
|
||||
};
|
||||
|
||||
// Convert thrust direction into nodes & emitters
|
||||
HoverVehicle::JetActivation HoverVehicle::sJetActivation[NumThrustDirections] = {
|
||||
{ HoverVehicleData::ForwardJetNode, HoverVehicleData::ForwardJetEmitter },
|
||||
{ HoverVehicleData::BackwardJetNode, HoverVehicleData::BackwardJetEmitter },
|
||||
{ HoverVehicleData::DownwardJetNode, HoverVehicleData::DownwardJetEmitter },
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------
|
||||
//
|
||||
HoverVehicleData::HoverVehicleData()
|
||||
{
|
||||
dragForce = 0;
|
||||
vertFactor = 0.25f;
|
||||
floatingThrustFactor = 0.15f;
|
||||
|
||||
mainThrustForce = 0;
|
||||
reverseThrustForce = 0;
|
||||
strafeThrustForce = 0;
|
||||
turboFactor = 1.0f;
|
||||
|
||||
stabLenMin = 0.5f;
|
||||
stabLenMax = 2.0f;
|
||||
stabSpringConstant = 30;
|
||||
stabDampingConstant = 10;
|
||||
|
||||
gyroDrag = 10;
|
||||
normalForce = 30;
|
||||
restorativeForce = 10;
|
||||
steeringForce = 25;
|
||||
rollForce = 2.5f;
|
||||
pitchForce = 2.5f;
|
||||
|
||||
dustTrailEmitter = NULL;
|
||||
dustTrailID = 0;
|
||||
dustTrailOffset.set( 0.0f, 0.0f, 0.0f );
|
||||
dustTrailFreqMod = 15.0f;
|
||||
triggerTrailHeight = 2.5f;
|
||||
|
||||
floatingGravMag = 1;
|
||||
brakingForce = 0;
|
||||
brakingActivationSpeed = 0;
|
||||
|
||||
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++)
|
||||
sound[i] = 0;
|
||||
}
|
||||
|
||||
HoverVehicleData::~HoverVehicleData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void HoverVehicleData::initPersistFields()
|
||||
{
|
||||
addField( "dragForce", TypeF32, Offset(dragForce, HoverVehicleData),
|
||||
"Drag force factor that acts opposite to the vehicle velocity.\nAlso "
|
||||
"used to determnine the vehicle's maxThrustSpeed.\n@see mainThrustForce" );
|
||||
addField( "vertFactor", TypeF32, Offset(vertFactor, HoverVehicleData),
|
||||
"Scalar applied to the vertical portion of the velocity drag acting on "
|
||||
"the vehicle.\nFor the horizontal (X and Y) components of velocity drag, "
|
||||
"a factor of 0.25 is applied when the vehicle is floating, and a factor "
|
||||
"of 1.0 is applied when the vehicle is not floating. This velocity drag "
|
||||
"is multiplied by the vehicle's dragForce, as defined above, and the "
|
||||
"result is subtracted from it's movement force.\n"
|
||||
"@note The vertFactor must be between 0.0 and 1.0 (inclusive)." );
|
||||
addField( "floatingThrustFactor", TypeF32, Offset(floatingThrustFactor, HoverVehicleData),
|
||||
"Scalar applied to the vehicle's thrust force when the vehicle is floating.\n"
|
||||
"@note The floatingThrustFactor must be between 0.0 and 1.0 (inclusive)." );
|
||||
addField( "mainThrustForce", TypeF32, Offset(mainThrustForce, HoverVehicleData),
|
||||
"Force generated by thrusting the vehicle forward.\nAlso used to determine "
|
||||
"the maxThrustSpeed:\n\n"
|
||||
"@tsexample\n"
|
||||
"maxThrustSpeed = (mainThrustForce + strafeThrustForce) / dragForce;\n"
|
||||
"@endtsexample\n" );
|
||||
addField( "reverseThrustForce", TypeF32, Offset(reverseThrustForce, HoverVehicleData),
|
||||
"Force generated by thrusting the vehicle backward." );
|
||||
addField( "strafeThrustForce", TypeF32, Offset(strafeThrustForce, HoverVehicleData),
|
||||
"Force generated by thrusting the vehicle to one side.\nAlso used to "
|
||||
"determine the vehicle's maxThrustSpeed.\n@see mainThrustForce" );
|
||||
addField( "turboFactor", TypeF32, Offset(turboFactor, HoverVehicleData),
|
||||
"Scale factor applied to the vehicle's thrust force when jetting." );
|
||||
|
||||
addField( "stabLenMin", TypeF32, Offset(stabLenMin, HoverVehicleData),
|
||||
"Length of the base stabalizer when travelling at minimum speed (0).\n"
|
||||
"Each tick, the vehicle performs 2 raycasts (from the center back and "
|
||||
"center front of the vehicle) to check for contact with the ground. The "
|
||||
"base stabalizer length determines the length of that raycast; if "
|
||||
"neither raycast hit the ground, the vehicle is floating, stabalizer "
|
||||
"spring and ground normal forces are not applied.\n\n"
|
||||
"<img src=\"images/hoverVehicle_forces.png\">\n"
|
||||
"@see stabSpringConstant" );
|
||||
addField( "stabLenMax", TypeF32, Offset(stabLenMax, HoverVehicleData),
|
||||
"Length of the base stabalizer when travelling at maximum speed "
|
||||
"(maxThrustSpeed).\n\n@see stabLenMin\n\n@see mainThrustForce" );
|
||||
|
||||
addField( "stabSpringConstant", TypeF32, Offset(stabSpringConstant, HoverVehicleData),
|
||||
"Value used to generate stabalizer spring force. The force generated "
|
||||
"depends on stabilizer compression, that is how close the vehicle is "
|
||||
"to the ground proportional to current stabalizer length.\n\n"
|
||||
"@see stabLenMin" );
|
||||
addField( "stabDampingConstant", TypeF32, Offset(stabDampingConstant, HoverVehicleData),
|
||||
"Damping spring force acting against changes in the stabalizer length.\n\n"
|
||||
"@see stabLenMin" );
|
||||
|
||||
addField( "gyroDrag", TypeF32, Offset(gyroDrag, HoverVehicleData),
|
||||
"Damping torque that acts against the vehicle's current angular momentum." );
|
||||
addField( "normalForce", TypeF32, Offset(normalForce, HoverVehicleData),
|
||||
"Force generated in the ground normal direction when the vehicle is not "
|
||||
"floating (within stabalizer length from the ground).\n\n"
|
||||
"@see stabLenMin" );
|
||||
addField( "restorativeForce", TypeF32, Offset(restorativeForce, HoverVehicleData),
|
||||
"Force generated to stabalize the vehicle (return it to neutral pitch/roll) "
|
||||
"when the vehicle is floating (more than stabalizer length from the "
|
||||
"ground.\n\n@see stabLenMin" );
|
||||
addField( "steeringForce", TypeF32, Offset(steeringForce, HoverVehicleData),
|
||||
"Yaw (rotation about the Z-axis) force applied when steering in the x-axis direction."
|
||||
"about the vehicle's Z-axis)" );
|
||||
addField( "rollForce", TypeF32, Offset(rollForce, HoverVehicleData),
|
||||
"Roll (rotation about the Y-axis) force applied when steering in the x-axis direction." );
|
||||
addField( "pitchForce", TypeF32, Offset(pitchForce, HoverVehicleData),
|
||||
"Pitch (rotation about the X-axis) force applied when steering in the y-axis direction." );
|
||||
|
||||
addField( "jetSound", TYPEID< SFXProfile >(), Offset(sound[JetSound], HoverVehicleData),
|
||||
"Looping sound played when the vehicle is jetting." );
|
||||
addField( "engineSound", TYPEID< SFXProfile >(), Offset(sound[EngineSound], HoverVehicleData),
|
||||
"Looping engine sound.\nThe volume is dynamically adjusted based on the "
|
||||
"current thrust level." );
|
||||
addField( "floatSound", TYPEID< SFXProfile >(), Offset(sound[FloatSound], HoverVehicleData),
|
||||
"Looping sound played while the vehicle is floating.\n\n@see stabMinLen" );
|
||||
|
||||
addField( "dustTrailEmitter", TYPEID< ParticleEmitterData >(), Offset(dustTrailEmitter, HoverVehicleData),
|
||||
"Emitter to generate particles for the vehicle's dust trail.\nThe trail "
|
||||
"of dust particles is generated only while the vehicle is moving." );
|
||||
addField( "dustTrailOffset", TypePoint3F, Offset(dustTrailOffset, HoverVehicleData),
|
||||
"\"X Y Z\" offset from the vehicle's origin from which to generate dust "
|
||||
"trail particles.\nBy default particles are emitted directly beneath the "
|
||||
"origin of the vehicle model." );
|
||||
addField( "triggerTrailHeight", TypeF32, Offset(triggerTrailHeight, HoverVehicleData),
|
||||
"Maximum height above surface to emit dust trail particles.\nIf the vehicle "
|
||||
"is less than triggerTrailHeight above a static surface with a material that "
|
||||
"has 'showDust' set to true, the vehicle will emit particles from the "
|
||||
"dustTrailEmitter." );
|
||||
addField( "dustTrailFreqMod", TypeF32, Offset(dustTrailFreqMod, HoverVehicleData),
|
||||
"Number of dust trail particles to generate based on vehicle speed.\nThe "
|
||||
"vehicle's speed is divided by this value to determine how many particles "
|
||||
"to generate each frame. Lower values give a more dense trail, higher "
|
||||
"values a more sparse trail." );
|
||||
|
||||
addField( "floatingGravMag", TypeF32, Offset(floatingGravMag, HoverVehicleData),
|
||||
"Scale factor applied to the vehicle gravitational force when the vehicle "
|
||||
"is floating.\n\n@see stabLenMin" );
|
||||
addField( "brakingForce", TypeF32, Offset(brakingForce, HoverVehicleData),
|
||||
"Force generated by braking.\nThe vehicle is considered to be braking if "
|
||||
"it is moving, but the throttle is off, and no left or right thrust is "
|
||||
"being applied. This force is only applied when the vehicle's velocity is "
|
||||
"less than brakingActivationSpeed." );
|
||||
addField( "brakingActivationSpeed", TypeF32, Offset(brakingActivationSpeed, HoverVehicleData),
|
||||
"Maximum speed below which a braking force is applied.\n\n@see brakingForce" );
|
||||
|
||||
addField( "forwardJetEmitter", TYPEID< ParticleEmitterData >(), Offset(jetEmitter[ForwardJetEmitter], HoverVehicleData),
|
||||
"Emitter to generate particles for forward jet thrust.\nForward jet "
|
||||
"thrust particles are emitted from model nodes JetNozzle0 and JetNozzle1." );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool HoverVehicleData::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool HoverVehicleData::preload(bool server, String &errorStr)
|
||||
{
|
||||
if (Parent::preload(server, errorStr) == false)
|
||||
return false;
|
||||
|
||||
if (dragForce <= 0.01f) {
|
||||
Con::warnf("HoverVehicleData::preload: dragForce must be at least 0.01");
|
||||
dragForce = 0.01f;
|
||||
}
|
||||
if (vertFactor < 0.0f || vertFactor > 1.0f) {
|
||||
Con::warnf("HoverVehicleData::preload: vert factor must be [0, 1]");
|
||||
vertFactor = vertFactor < 0.0f ? 0.0f : 1.0f;
|
||||
}
|
||||
if (floatingThrustFactor < 0.0f || floatingThrustFactor > 1.0f) {
|
||||
Con::warnf("HoverVehicleData::preload: floatingThrustFactor must be [0, 1]");
|
||||
floatingThrustFactor = floatingThrustFactor < 0.0f ? 0.0f : 1.0f;
|
||||
}
|
||||
|
||||
maxThrustSpeed = (mainThrustForce + strafeThrustForce) / dragForce;
|
||||
|
||||
massCenter = Point3F(0, 0, 0);
|
||||
|
||||
// Resolve objects transmitted from server
|
||||
if (!server) {
|
||||
for (S32 i = 0; i < MaxSounds; i++)
|
||||
if (sound[i])
|
||||
Sim::findObject(SimObjectId(sound[i]),sound[i]);
|
||||
for (S32 j = 0; j < MaxJetEmitters; j++)
|
||||
if (jetEmitter[j])
|
||||
Sim::findObject(SimObjectId(jetEmitter[j]),jetEmitter[j]);
|
||||
}
|
||||
|
||||
if( !dustTrailEmitter && dustTrailID != 0 )
|
||||
{
|
||||
if( !Sim::findObject( dustTrailID, dustTrailEmitter ) )
|
||||
{
|
||||
Con::errorf( ConsoleLogEntry::General, "HoverVehicleData::preload Invalid packet, bad datablockId(dustTrailEmitter): 0x%x", dustTrailID );
|
||||
}
|
||||
}
|
||||
// Resolve jet nodes
|
||||
for (S32 j = 0; j < MaxJetNodes; j++)
|
||||
jetNode[j] = mShape->findNode(sJetNode[j]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void HoverVehicleData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
stream->write(dragForce);
|
||||
stream->write(vertFactor);
|
||||
stream->write(floatingThrustFactor);
|
||||
stream->write(mainThrustForce);
|
||||
stream->write(reverseThrustForce);
|
||||
stream->write(strafeThrustForce);
|
||||
stream->write(turboFactor);
|
||||
stream->write(stabLenMin);
|
||||
stream->write(stabLenMax);
|
||||
stream->write(stabSpringConstant);
|
||||
stream->write(stabDampingConstant);
|
||||
stream->write(gyroDrag);
|
||||
stream->write(normalForce);
|
||||
stream->write(restorativeForce);
|
||||
stream->write(steeringForce);
|
||||
stream->write(rollForce);
|
||||
stream->write(pitchForce);
|
||||
mathWrite(*stream, dustTrailOffset);
|
||||
stream->write(triggerTrailHeight);
|
||||
stream->write(dustTrailFreqMod);
|
||||
|
||||
for (S32 i = 0; i < MaxSounds; i++)
|
||||
if (stream->writeFlag(sound[i]))
|
||||
stream->writeRangedU32(packed? SimObjectId(sound[i]):
|
||||
sound[i]->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
|
||||
|
||||
for (S32 j = 0; j < MaxJetEmitters; j++)
|
||||
{
|
||||
if (stream->writeFlag(jetEmitter[j]))
|
||||
{
|
||||
SimObjectId writtenId = packed ? SimObjectId(jetEmitter[j]) : jetEmitter[j]->getId();
|
||||
stream->writeRangedU32(writtenId, DataBlockObjectIdFirst,DataBlockObjectIdLast);
|
||||
}
|
||||
}
|
||||
|
||||
if (stream->writeFlag( dustTrailEmitter ))
|
||||
{
|
||||
stream->writeRangedU32( dustTrailEmitter->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast );
|
||||
}
|
||||
stream->write(floatingGravMag);
|
||||
stream->write(brakingForce);
|
||||
stream->write(brakingActivationSpeed);
|
||||
}
|
||||
|
||||
|
||||
void HoverVehicleData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
|
||||
stream->read(&dragForce);
|
||||
stream->read(&vertFactor);
|
||||
stream->read(&floatingThrustFactor);
|
||||
stream->read(&mainThrustForce);
|
||||
stream->read(&reverseThrustForce);
|
||||
stream->read(&strafeThrustForce);
|
||||
stream->read(&turboFactor);
|
||||
stream->read(&stabLenMin);
|
||||
stream->read(&stabLenMax);
|
||||
stream->read(&stabSpringConstant);
|
||||
stream->read(&stabDampingConstant);
|
||||
stream->read(&gyroDrag);
|
||||
stream->read(&normalForce);
|
||||
stream->read(&restorativeForce);
|
||||
stream->read(&steeringForce);
|
||||
stream->read(&rollForce);
|
||||
stream->read(&pitchForce);
|
||||
mathRead(*stream, &dustTrailOffset);
|
||||
stream->read(&triggerTrailHeight);
|
||||
stream->read(&dustTrailFreqMod);
|
||||
|
||||
for (S32 i = 0; i < MaxSounds; i++)
|
||||
sound[i] = stream->readFlag()?
|
||||
(SFXProfile*) stream->readRangedU32(DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast): 0;
|
||||
|
||||
for (S32 j = 0; j < MaxJetEmitters; j++) {
|
||||
jetEmitter[j] = NULL;
|
||||
if (stream->readFlag())
|
||||
jetEmitter[j] = (ParticleEmitterData*)stream->readRangedU32(DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
}
|
||||
|
||||
if( stream->readFlag() )
|
||||
{
|
||||
dustTrailID = (S32) stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
}
|
||||
stream->read(&floatingGravMag);
|
||||
stream->read(&brakingForce);
|
||||
stream->read(&brakingActivationSpeed);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------
|
||||
//
|
||||
HoverVehicle::HoverVehicle()
|
||||
{
|
||||
// Todo: ScopeAlways?
|
||||
mNetFlags.set(Ghostable);
|
||||
|
||||
mFloating = false;
|
||||
mForwardThrust = 0;
|
||||
mReverseThrust = 0;
|
||||
mLeftThrust = 0;
|
||||
mRightThrust = 0;
|
||||
|
||||
mJetSound = NULL;
|
||||
mEngineSound = NULL;
|
||||
mFloatSound = NULL;
|
||||
|
||||
mDustTrailEmitter = NULL;
|
||||
|
||||
mBackMaintainOn = false;
|
||||
for (S32 i = 0; i < JetAnimCount; i++)
|
||||
mJetThread[i] = 0;
|
||||
}
|
||||
|
||||
HoverVehicle::~HoverVehicle()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool HoverVehicle::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
addToScene();
|
||||
|
||||
|
||||
if( !isServerObject() )
|
||||
{
|
||||
if( mDataBlock->dustTrailEmitter )
|
||||
{
|
||||
mDustTrailEmitter = new ParticleEmitter;
|
||||
mDustTrailEmitter->onNewDataBlock( mDataBlock->dustTrailEmitter, false );
|
||||
if( !mDustTrailEmitter->registerObject() )
|
||||
{
|
||||
Con::warnf( ConsoleLogEntry::General, "Could not register dust emitter for class: %s", mDataBlock->getName() );
|
||||
delete mDustTrailEmitter;
|
||||
mDustTrailEmitter = NULL;
|
||||
}
|
||||
}
|
||||
// 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) {
|
||||
mJetThread[i] = mShapeInstance->addThread();
|
||||
mShapeInstance->setSequence(mJetThread[i],mJetSeq[i],0);
|
||||
mShapeInstance->setTimeScale(mJetThread[i],0);
|
||||
}
|
||||
}
|
||||
else
|
||||
mJetThread[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isServerObject())
|
||||
scriptOnAdd();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void HoverVehicle::onRemove()
|
||||
{
|
||||
SFX_DELETE( mJetSound );
|
||||
SFX_DELETE( mEngineSound );
|
||||
SFX_DELETE( mFloatSound );
|
||||
|
||||
scriptOnRemove();
|
||||
removeFromScene();
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
|
||||
bool HoverVehicle::onNewDataBlock(GameBaseData* dptr, bool reload)
|
||||
{
|
||||
mDataBlock = dynamic_cast<HoverVehicleData*>(dptr);
|
||||
if (!mDataBlock || !Parent::onNewDataBlock(dptr,reload))
|
||||
return false;
|
||||
|
||||
if (isGhost())
|
||||
{
|
||||
// Create the sounds ahead of time. This reduces runtime
|
||||
// costs and makes the system easier to understand.
|
||||
|
||||
SFX_DELETE( mEngineSound );
|
||||
SFX_DELETE( mFloatSound );
|
||||
SFX_DELETE( mJetSound );
|
||||
|
||||
if ( mDataBlock->sound[HoverVehicleData::EngineSound] )
|
||||
mEngineSound = SFX->createSource( mDataBlock->sound[HoverVehicleData::EngineSound], &getTransform() );
|
||||
|
||||
if ( !mDataBlock->sound[HoverVehicleData::FloatSound] )
|
||||
mFloatSound = SFX->createSource( mDataBlock->sound[HoverVehicleData::FloatSound], &getTransform() );
|
||||
|
||||
if ( mDataBlock->sound[HoverVehicleData::JetSound] )
|
||||
mJetSound = SFX->createSource( mDataBlock->sound[HoverVehicleData::JetSound], &getTransform() );
|
||||
}
|
||||
|
||||
// Todo: Uncomment if this is a "leaf" class
|
||||
scriptOnNewDataBlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void HoverVehicle::advanceTime(F32 dt)
|
||||
{
|
||||
Parent::advanceTime(dt);
|
||||
|
||||
// Update jetsound...
|
||||
if ( mJetSound )
|
||||
{
|
||||
if ( mJetting )
|
||||
{
|
||||
if ( !mJetSound->isPlaying() )
|
||||
mJetSound->play();
|
||||
|
||||
mJetSound->setTransform( getTransform() );
|
||||
}
|
||||
else
|
||||
mJetSound->stop();
|
||||
}
|
||||
|
||||
// Update engine sound...
|
||||
if ( mEngineSound )
|
||||
{
|
||||
if ( !mEngineSound->isPlaying() )
|
||||
mEngineSound->play();
|
||||
|
||||
mEngineSound->setTransform( getTransform() );
|
||||
|
||||
F32 denom = mDataBlock->mainThrustForce + mDataBlock->strafeThrustForce;
|
||||
F32 factor = getMin(mThrustLevel, denom) / denom;
|
||||
F32 vol = 0.25 + factor * 0.75;
|
||||
mEngineSound->setVolume( vol );
|
||||
}
|
||||
|
||||
// Are we floating? If so, start the floating sound...
|
||||
if ( mFloatSound )
|
||||
{
|
||||
if ( mFloating )
|
||||
{
|
||||
if ( !mFloatSound->isPlaying() )
|
||||
mFloatSound->play();
|
||||
|
||||
mFloatSound->setTransform( getTransform() );
|
||||
}
|
||||
else
|
||||
mFloatSound->stop();
|
||||
}
|
||||
|
||||
updateJet(dt);
|
||||
updateDustTrail( dt );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
U32 HoverVehicle::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
|
||||
{
|
||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
|
||||
//
|
||||
stream->writeInt(mThrustDirection,NumThrustBits);
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
void HoverVehicle::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||
{
|
||||
Parent::unpackUpdate(con, stream);
|
||||
|
||||
mThrustDirection = ThrustDirection(stream->readInt(NumThrustBits));
|
||||
//
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void HoverVehicle::updateMove(const Move* move)
|
||||
{
|
||||
Parent::updateMove(move);
|
||||
|
||||
mForwardThrust = mThrottle > 0.0f ? mThrottle : 0.0f;
|
||||
mReverseThrust = mThrottle < 0.0f ? -mThrottle : 0.0f;
|
||||
mLeftThrust = move->x < 0.0f ? -move->x : 0.0f;
|
||||
mRightThrust = move->x > 0.0f ? move->x : 0.0f;
|
||||
|
||||
mThrustDirection = (!move->y)? ThrustDown: (move->y > 0)? ThrustForward: ThrustBackward;
|
||||
}
|
||||
|
||||
F32 HoverVehicle::getBaseStabilizerLength() const
|
||||
{
|
||||
F32 base = mDataBlock->stabLenMin;
|
||||
F32 lengthDiff = mDataBlock->stabLenMax - mDataBlock->stabLenMin;
|
||||
F32 velLength = mRigid.linVelocity.len();
|
||||
F32 minVel = getMin(velLength, mDataBlock->maxThrustSpeed);
|
||||
F32 velDiff = mDataBlock->maxThrustSpeed - minVel;
|
||||
// Protect against divide by zero.
|
||||
F32 velRatio = mDataBlock->maxThrustSpeed != 0.0f ? ( velDiff / mDataBlock->maxThrustSpeed ) : 0.0f;
|
||||
F32 inc = lengthDiff * ( 1.0 - velRatio );
|
||||
base += inc;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
|
||||
struct StabPoint
|
||||
{
|
||||
Point3F osPoint; //
|
||||
Point3F wsPoint; //
|
||||
F32 extension;
|
||||
Point3F wsExtension; //
|
||||
Point3F wsVelocity; //
|
||||
};
|
||||
|
||||
|
||||
void HoverVehicle::updateForces(F32 /*dt*/)
|
||||
{
|
||||
PROFILE_SCOPE( HoverVehicle_UpdateForces );
|
||||
|
||||
Point3F gravForce(0, 0, sHoverVehicleGravity * mRigid.mass * mGravityMod);
|
||||
|
||||
MatrixF currTransform;
|
||||
mRigid.getTransform(&currTransform);
|
||||
mRigid.atRest = false;
|
||||
|
||||
mThrustLevel = (mForwardThrust * mDataBlock->mainThrustForce +
|
||||
mReverseThrust * mDataBlock->reverseThrustForce +
|
||||
mLeftThrust * mDataBlock->strafeThrustForce +
|
||||
mRightThrust * mDataBlock->strafeThrustForce);
|
||||
|
||||
Point3F thrustForce = ((Point3F( 0, 1, 0) * (mForwardThrust * mDataBlock->mainThrustForce)) +
|
||||
(Point3F( 0, -1, 0) * (mReverseThrust * mDataBlock->reverseThrustForce)) +
|
||||
(Point3F(-1, 0, 0) * (mLeftThrust * mDataBlock->strafeThrustForce)) +
|
||||
(Point3F( 1, 0, 0) * (mRightThrust * mDataBlock->strafeThrustForce)));
|
||||
currTransform.mulV(thrustForce);
|
||||
if (mJetting)
|
||||
thrustForce *= mDataBlock->turboFactor;
|
||||
|
||||
Point3F torque(0, 0, 0);
|
||||
Point3F force(0, 0, 0);
|
||||
|
||||
Point3F vel = mRigid.linVelocity;
|
||||
F32 baseStabLen = getBaseStabilizerLength();
|
||||
Point3F stabExtend(0, 0, -baseStabLen);
|
||||
currTransform.mulV(stabExtend);
|
||||
|
||||
StabPoint stabPoints[2];
|
||||
stabPoints[0].osPoint = Point3F((mObjBox.minExtents.x + mObjBox.maxExtents.x) * 0.5,
|
||||
mObjBox.maxExtents.y,
|
||||
(mObjBox.minExtents.z + mObjBox.maxExtents.z) * 0.5);
|
||||
stabPoints[1].osPoint = Point3F((mObjBox.minExtents.x + mObjBox.maxExtents.x) * 0.5,
|
||||
mObjBox.minExtents.y,
|
||||
(mObjBox.minExtents.z + mObjBox.maxExtents.z) * 0.5);
|
||||
U32 j, i;
|
||||
for (i = 0; i < 2; i++) {
|
||||
currTransform.mulP(stabPoints[i].osPoint, &stabPoints[i].wsPoint);
|
||||
stabPoints[i].wsExtension = stabExtend;
|
||||
stabPoints[i].extension = baseStabLen;
|
||||
stabPoints[i].wsVelocity = mRigid.linVelocity;
|
||||
}
|
||||
|
||||
RayInfo rinfo;
|
||||
|
||||
mFloating = true;
|
||||
bool reallyFloating = true;
|
||||
F32 compression[2] = { 0.0f, 0.0f };
|
||||
F32 normalMod[2] = { 0.0f, 0.0f };
|
||||
bool normalSet[2] = { false, false };
|
||||
Point3F normal[2];
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
if (getContainer()->castRay(stabPoints[j].wsPoint, stabPoints[j].wsPoint + stabPoints[j].wsExtension * 2.0,
|
||||
TerrainObjectType |
|
||||
InteriorObjectType | WaterObjectType, &rinfo))
|
||||
{
|
||||
reallyFloating = false;
|
||||
|
||||
if (rinfo.t <= 0.5) {
|
||||
// Ok, stab is in contact with the ground, let's calc the forces...
|
||||
compression[j] = (1.0 - (rinfo.t * 2.0)) * baseStabLen;
|
||||
}
|
||||
normalSet[j] = true;
|
||||
normalMod[j] = rinfo.t < 0.5 ? 1.0 : (1.0 - ((rinfo.t - 0.5) * 2.0));
|
||||
|
||||
normal[j] = rinfo.normal;
|
||||
}
|
||||
|
||||
if ( pointInWater( stabPoints[j].wsPoint ) )
|
||||
compression[j] = baseStabLen;
|
||||
}
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
if (compression[j] != 0.0) {
|
||||
mFloating = false;
|
||||
|
||||
// Spring force and damping
|
||||
Point3F springForce = -stabPoints[j].wsExtension;
|
||||
springForce.normalize();
|
||||
springForce *= compression[j] * mDataBlock->stabSpringConstant;
|
||||
|
||||
Point3F springDamping = -stabPoints[j].wsExtension;
|
||||
springDamping.normalize();
|
||||
springDamping *= -getMin(mDot(springDamping, stabPoints[j].wsVelocity), 0.7f) * mDataBlock->stabDampingConstant;
|
||||
|
||||
force += springForce + springDamping;
|
||||
}
|
||||
}
|
||||
|
||||
// Gravity
|
||||
if (reallyFloating == false)
|
||||
force += gravForce;
|
||||
else
|
||||
force += gravForce * mDataBlock->floatingGravMag;
|
||||
|
||||
// Braking
|
||||
F32 vellen = mRigid.linVelocity.len();
|
||||
if (mThrottle == 0.0f &&
|
||||
mLeftThrust == 0.0f &&
|
||||
mRightThrust == 0.0f &&
|
||||
vellen != 0.0f &&
|
||||
vellen < mDataBlock->brakingActivationSpeed)
|
||||
{
|
||||
Point3F dir = mRigid.linVelocity;
|
||||
dir.normalize();
|
||||
dir.neg();
|
||||
force += dir * mDataBlock->brakingForce;
|
||||
}
|
||||
|
||||
// Gyro Drag
|
||||
torque = -mRigid.angMomentum * mDataBlock->gyroDrag;
|
||||
|
||||
// Move to proper normal
|
||||
Point3F sn, r;
|
||||
currTransform.getColumn(2, &sn);
|
||||
if (normalSet[0] || normalSet[1]) {
|
||||
if (normalSet[0] && normalSet[1]) {
|
||||
F32 dot = mDot(normal[0], normal[1]);
|
||||
if (dot > 0.999) {
|
||||
// Just pick the first normal. They're too close to call
|
||||
if ((sn - normal[0]).lenSquared() > 0.00001) {
|
||||
mCross(sn, normal[0], &r);
|
||||
torque += r * mDataBlock->normalForce * normalMod[0];
|
||||
}
|
||||
} else {
|
||||
Point3F rotAxis;
|
||||
mCross(normal[0], normal[1], &rotAxis);
|
||||
rotAxis.normalize();
|
||||
|
||||
F32 angle = mAcos(dot) * (normalMod[0] / (normalMod[0] + normalMod[1]));
|
||||
AngAxisF aa(rotAxis, angle);
|
||||
QuatF q(aa);
|
||||
MatrixF tempMat(true);
|
||||
q.setMatrix(&tempMat);
|
||||
Point3F newNormal;
|
||||
tempMat.mulV(normal[1], &newNormal);
|
||||
|
||||
if ((sn - newNormal).lenSquared() > 0.00001) {
|
||||
mCross(sn, newNormal, &r);
|
||||
torque += r * (mDataBlock->normalForce * ((normalMod[0] + normalMod[1]) * 0.5));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Point3F useNormal;
|
||||
F32 useMod;
|
||||
if (normalSet[0]) {
|
||||
useNormal = normal[0];
|
||||
useMod = normalMod[0];
|
||||
} else {
|
||||
useNormal = normal[1];
|
||||
useMod = normalMod[1];
|
||||
}
|
||||
|
||||
if ((sn - useNormal).lenSquared() > 0.00001) {
|
||||
mCross(sn, useNormal, &r);
|
||||
torque += r * mDataBlock->normalForce * useMod;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((sn - Point3F(0, 0, 1)).lenSquared() > 0.00001) {
|
||||
mCross(sn, Point3F(0, 0, 1), &r);
|
||||
torque += r * mDataBlock->restorativeForce;
|
||||
}
|
||||
}
|
||||
|
||||
Point3F sn2;
|
||||
currTransform.getColumn(0, &sn);
|
||||
currTransform.getColumn(1, &sn2);
|
||||
mCross(sn, sn2, &r);
|
||||
r.normalize();
|
||||
torque -= r * (mSteering.x * mDataBlock->steeringForce);
|
||||
|
||||
currTransform.getColumn(0, &sn);
|
||||
currTransform.getColumn(2, &sn2);
|
||||
mCross(sn, sn2, &r);
|
||||
r.normalize();
|
||||
torque -= r * (mSteering.x * mDataBlock->rollForce);
|
||||
|
||||
currTransform.getColumn(1, &sn);
|
||||
currTransform.getColumn(2, &sn2);
|
||||
mCross(sn, sn2, &r);
|
||||
r.normalize();
|
||||
torque -= r * (mSteering.y * mDataBlock->pitchForce);
|
||||
|
||||
// Apply drag
|
||||
Point3F vDrag = mRigid.linVelocity;
|
||||
if (!mFloating) {
|
||||
vDrag.convolve(Point3F(1, 1, mDataBlock->vertFactor));
|
||||
} else {
|
||||
vDrag.convolve(Point3F(0.25, 0.25, mDataBlock->vertFactor));
|
||||
}
|
||||
force -= vDrag * mDataBlock->dragForce;
|
||||
|
||||
force += mFloating ? thrustForce * mDataBlock->floatingThrustFactor : thrustForce;
|
||||
|
||||
// Add in physical zone force
|
||||
force += mAppliedForce;
|
||||
|
||||
// Container buoyancy & drag
|
||||
force += Point3F(0, 0,-mBuoyancy * sHoverVehicleGravity * mRigid.mass * mGravityMod);
|
||||
force -= mRigid.linVelocity * mDrag;
|
||||
torque -= mRigid.angMomentum * mDrag;
|
||||
|
||||
mRigid.force = force;
|
||||
mRigid.torque = torque;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
U32 HoverVehicle::getCollisionMask()
|
||||
{
|
||||
if (isServerObject())
|
||||
return sServerCollisionMask;
|
||||
else
|
||||
return sClientCollisionMask;
|
||||
}
|
||||
|
||||
void HoverVehicle::updateDustTrail( F32 dt )
|
||||
{
|
||||
// Check to see if we're moving.
|
||||
|
||||
VectorF velocityVector = getVelocity();
|
||||
F32 velocity = velocityVector.len();
|
||||
|
||||
if( velocity > 2.0 )
|
||||
{
|
||||
velocityVector.normalize();
|
||||
emitDust( mDustTrailEmitter, mDataBlock->triggerTrailHeight, mDataBlock->dustTrailOffset,
|
||||
( U32 )( dt * 1000 * ( velocity / mDataBlock->dustTrailFreqMod ) ),
|
||||
velocityVector );
|
||||
}
|
||||
}
|
||||
|
||||
void HoverVehicle::updateJet(F32 dt)
|
||||
{
|
||||
if (mJetThread[BackActivate] == NULL)
|
||||
return;
|
||||
|
||||
// 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.0f)
|
||||
{
|
||||
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]);
|
||||
|
||||
// Jet particles
|
||||
for (S32 j = 0; j < NumThrustDirections; j++) {
|
||||
JetActivation& jet = sJetActivation[j];
|
||||
updateEmitter(mJetting && j == mThrustDirection,dt,mDataBlock->jetEmitter[jet.emitter],
|
||||
jet.node,HoverVehicleData::MaxDirectionJets);
|
||||
}
|
||||
}
|
||||
|
||||
void HoverVehicle::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.0f));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (S32 j = idx; j < idx + count; j++)
|
||||
if (bool(mJetEmitter[j])) {
|
||||
mJetEmitter[j]->deleteWhenEmpty();
|
||||
mJetEmitter[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
213
Engine/source/T3D/vehicles/hoverVehicle.h
Normal file
213
Engine/source/T3D/vehicles/hoverVehicle.h
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _HOVERVEHICLE_H_
|
||||
#define _HOVERVEHICLE_H_
|
||||
|
||||
#ifndef _VEHICLE_H_
|
||||
#include "T3D/vehicles/vehicle.h"
|
||||
#endif
|
||||
|
||||
class ParticleEmitter;
|
||||
class ParticleEmitterData;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
class HoverVehicleData : public VehicleData
|
||||
{
|
||||
typedef VehicleData Parent;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
|
||||
//-------------------------------------- Console set variables
|
||||
public:
|
||||
enum Sounds {
|
||||
JetSound,
|
||||
EngineSound,
|
||||
FloatSound,
|
||||
MaxSounds
|
||||
};
|
||||
SFXProfile* sound[MaxSounds];
|
||||
|
||||
enum Jets {
|
||||
// These enums index into a static name list.
|
||||
ForwardJetEmitter, // Thrust forward
|
||||
BackwardJetEmitter, // Thrust backward
|
||||
DownwardJetEmitter, // Thrust down
|
||||
MaxJetEmitters,
|
||||
};
|
||||
ParticleEmitterData* jetEmitter[MaxJetEmitters];
|
||||
|
||||
enum JetNodes {
|
||||
// These enums index into a static name list.
|
||||
ForwardJetNode,
|
||||
ForwardJetNode1,
|
||||
BackwardJetNode,
|
||||
BackwardJetNode1,
|
||||
DownwardJetNode,
|
||||
DownwardJetNode1,
|
||||
//
|
||||
MaxJetNodes,
|
||||
MaxDirectionJets = 2,
|
||||
ThrustJetStart = ForwardJetNode,
|
||||
MaxTrails = 4,
|
||||
};
|
||||
static const char *sJetNode[MaxJetNodes];
|
||||
S32 jetNode[MaxJetNodes];
|
||||
|
||||
|
||||
F32 dragForce;
|
||||
F32 vertFactor;
|
||||
F32 floatingThrustFactor;
|
||||
|
||||
F32 mainThrustForce;
|
||||
F32 reverseThrustForce;
|
||||
F32 strafeThrustForce;
|
||||
F32 turboFactor;
|
||||
|
||||
F32 stabLenMin;
|
||||
F32 stabLenMax;
|
||||
F32 stabSpringConstant;
|
||||
F32 stabDampingConstant;
|
||||
|
||||
F32 gyroDrag;
|
||||
F32 normalForce;
|
||||
F32 restorativeForce;
|
||||
F32 steeringForce;
|
||||
F32 rollForce;
|
||||
F32 pitchForce;
|
||||
|
||||
F32 floatingGravMag;
|
||||
|
||||
F32 brakingForce;
|
||||
F32 brakingActivationSpeed;
|
||||
|
||||
ParticleEmitterData * dustTrailEmitter;
|
||||
S32 dustTrailID;
|
||||
Point3F dustTrailOffset;
|
||||
F32 triggerTrailHeight;
|
||||
F32 dustTrailFreqMod;
|
||||
|
||||
//-------------------------------------- load set variables
|
||||
public:
|
||||
F32 maxThrustSpeed;
|
||||
|
||||
public:
|
||||
HoverVehicleData();
|
||||
~HoverVehicleData();
|
||||
|
||||
void packData(BitStream*);
|
||||
void unpackData(BitStream*);
|
||||
bool preload(bool server, String &errorStr);
|
||||
|
||||
DECLARE_CONOBJECT(HoverVehicleData);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
class HoverVehicle : public Vehicle
|
||||
{
|
||||
typedef Vehicle Parent;
|
||||
|
||||
private:
|
||||
HoverVehicleData* mDataBlock;
|
||||
SimObjectPtr<ParticleEmitter> mDustTrailEmitter;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
bool onNewDataBlock(GameBaseData *dptr,bool reload);
|
||||
void updateDustTrail( F32 dt );
|
||||
|
||||
// Vehicle overrides
|
||||
protected:
|
||||
void updateMove(const Move *move);
|
||||
|
||||
// Physics
|
||||
protected:
|
||||
void updateForces(F32);
|
||||
F32 getBaseStabilizerLength() const;
|
||||
|
||||
bool mFloating;
|
||||
F32 mThrustLevel;
|
||||
|
||||
F32 mForwardThrust;
|
||||
F32 mReverseThrust;
|
||||
F32 mLeftThrust;
|
||||
F32 mRightThrust;
|
||||
|
||||
SFXSource* mJetSound;
|
||||
SFXSource* mEngineSound;
|
||||
SFXSource* mFloatSound;
|
||||
|
||||
enum ThrustDirection {
|
||||
// Enums index into sJetActivationTable
|
||||
ThrustForward,
|
||||
ThrustBackward,
|
||||
ThrustDown,
|
||||
NumThrustDirections,
|
||||
NumThrustBits = 3
|
||||
};
|
||||
ThrustDirection mThrustDirection;
|
||||
|
||||
// Jet Threads
|
||||
enum Jets {
|
||||
// These enums index into a static name list.
|
||||
BackActivate,
|
||||
BackMaintain,
|
||||
JetAnimCount
|
||||
};
|
||||
static const char* sJetSequence[HoverVehicle::JetAnimCount];
|
||||
TSThread* mJetThread[JetAnimCount];
|
||||
S32 mJetSeq[JetAnimCount];
|
||||
bool mBackMaintainOn;
|
||||
|
||||
// Jet Particles
|
||||
struct JetActivation {
|
||||
// Convert thrust direction into nodes & emitters
|
||||
S32 node;
|
||||
S32 emitter;
|
||||
};
|
||||
static JetActivation sJetActivation[NumThrustDirections];
|
||||
SimObjectPtr<ParticleEmitter> mJetEmitter[HoverVehicleData::MaxJetNodes];
|
||||
|
||||
U32 getCollisionMask();
|
||||
void updateJet(F32 dt);
|
||||
void updateEmitter(bool active,F32 dt,ParticleEmitterData *emitter,S32 idx,S32 count);
|
||||
public:
|
||||
HoverVehicle();
|
||||
~HoverVehicle();
|
||||
|
||||
// Time/Move Management
|
||||
public:
|
||||
void advanceTime(F32 dt);
|
||||
|
||||
DECLARE_CONOBJECT(HoverVehicle);
|
||||
// static void initPersistFields();
|
||||
|
||||
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
};
|
||||
|
||||
#endif // _H_HOVERVEHICLE
|
||||
|
||||
1965
Engine/source/T3D/vehicles/vehicle.cpp
Normal file
1965
Engine/source/T3D/vehicles/vehicle.cpp
Normal file
File diff suppressed because it is too large
Load diff
306
Engine/source/T3D/vehicles/vehicle.h
Normal file
306
Engine/source/T3D/vehicles/vehicle.h
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _VEHICLE_H_
|
||||
#define _VEHICLE_H_
|
||||
|
||||
#ifndef _SHAPEBASE_H_
|
||||
#include "T3D/shapeBase.h"
|
||||
#endif
|
||||
#ifndef _RIGID_H_
|
||||
#include "T3D/rigid.h"
|
||||
#endif
|
||||
#ifndef _BOXCONVEX_H_
|
||||
#include "collision/boxConvex.h"
|
||||
#endif
|
||||
|
||||
class ParticleEmitter;
|
||||
class ParticleEmitterData;
|
||||
class ClippedPolyList;
|
||||
struct RenderInst;
|
||||
class Vehicle;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
struct VehicleData: public ShapeBaseData
|
||||
{
|
||||
typedef ShapeBaseData Parent;
|
||||
|
||||
struct Body {
|
||||
enum Sounds {
|
||||
SoftImpactSound,
|
||||
HardImpactSound,
|
||||
MaxSounds,
|
||||
};
|
||||
SFXProfile* sound[MaxSounds];
|
||||
F32 restitution;
|
||||
F32 friction;
|
||||
} body;
|
||||
|
||||
enum VehicleConsts
|
||||
{
|
||||
VC_NUM_DUST_EMITTERS = 1,
|
||||
VC_NUM_DAMAGE_EMITTER_AREAS = 2,
|
||||
VC_NUM_DAMAGE_LEVELS = 2,
|
||||
VC_NUM_BUBBLE_EMITTERS = 1,
|
||||
VC_NUM_DAMAGE_EMITTERS = VC_NUM_DAMAGE_LEVELS + VC_NUM_BUBBLE_EMITTERS,
|
||||
VC_NUM_SPLASH_EMITTERS = 2,
|
||||
VC_BUBBLE_EMITTER = VC_NUM_DAMAGE_EMITTERS - VC_NUM_BUBBLE_EMITTERS,
|
||||
};
|
||||
|
||||
enum Sounds {
|
||||
ExitWater,
|
||||
ImpactSoft,
|
||||
ImpactMedium,
|
||||
ImpactHard,
|
||||
Wake,
|
||||
MaxSounds
|
||||
};
|
||||
SFXProfile* waterSound[MaxSounds];
|
||||
F32 exitSplashSoundVel;
|
||||
F32 softSplashSoundVel;
|
||||
F32 medSplashSoundVel;
|
||||
F32 hardSplashSoundVel;
|
||||
|
||||
F32 minImpactSpeed;
|
||||
F32 softImpactSpeed;
|
||||
F32 hardImpactSpeed;
|
||||
F32 minRollSpeed;
|
||||
F32 maxSteeringAngle;
|
||||
|
||||
F32 collDamageThresholdVel;
|
||||
F32 collDamageMultiplier;
|
||||
|
||||
bool cameraRoll; ///< Roll the 3rd party camera
|
||||
F32 cameraLag; ///< Amount of camera lag (lag += car velocity * lag)
|
||||
F32 cameraDecay; ///< Rate at which camera returns to target pos.
|
||||
F32 cameraOffset; ///< Vertical offset
|
||||
|
||||
F32 minDrag;
|
||||
F32 maxDrag;
|
||||
S32 integration; ///< # of physics steps per tick
|
||||
F32 collisionTol; ///< Collision distance tolerance
|
||||
F32 contactTol; ///< Contact velocity tolerance
|
||||
Point3F massCenter; ///< Center of mass for rigid body
|
||||
Point3F massBox; ///< Size of inertial box
|
||||
|
||||
F32 jetForce;
|
||||
F32 jetEnergyDrain; ///< Energy drain/tick
|
||||
F32 minJetEnergy;
|
||||
|
||||
ParticleEmitterData * dustEmitter;
|
||||
S32 dustID;
|
||||
F32 triggerDustHeight; ///< height vehicle has to be under to kick up dust
|
||||
F32 dustHeight; ///< dust height above ground
|
||||
|
||||
ParticleEmitterData * damageEmitterList[ VC_NUM_DAMAGE_EMITTERS ];
|
||||
Point3F damageEmitterOffset[ VC_NUM_DAMAGE_EMITTER_AREAS ];
|
||||
S32 damageEmitterIDList[ VC_NUM_DAMAGE_EMITTERS ];
|
||||
F32 damageLevelTolerance[ VC_NUM_DAMAGE_LEVELS ];
|
||||
F32 numDmgEmitterAreas;
|
||||
|
||||
ParticleEmitterData* splashEmitterList[VC_NUM_SPLASH_EMITTERS];
|
||||
S32 splashEmitterIDList[VC_NUM_SPLASH_EMITTERS];
|
||||
F32 splashFreqMod;
|
||||
F32 splashVelEpsilon;
|
||||
|
||||
//
|
||||
VehicleData();
|
||||
bool preload(bool server, String &errorStr);
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
|
||||
DECLARE_CONOBJECT(VehicleData);
|
||||
|
||||
DECLARE_CALLBACK( void, onEnterLiquid, ( Vehicle* obj, F32 coverage, const char* type ) );
|
||||
DECLARE_CALLBACK( void, onLeaveLiquid, ( Vehicle* obj, const char* type ) );
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class Vehicle: public ShapeBase
|
||||
{
|
||||
typedef ShapeBase Parent;
|
||||
|
||||
protected:
|
||||
enum CollisionFaceFlags {
|
||||
BodyCollision = 0x1,
|
||||
WheelCollision = 0x2,
|
||||
};
|
||||
enum MaskBits {
|
||||
PositionMask = Parent::NextFreeMask << 0,
|
||||
EnergyMask = Parent::NextFreeMask << 1,
|
||||
NextFreeMask = Parent::NextFreeMask << 2
|
||||
};
|
||||
|
||||
struct StateDelta {
|
||||
Move move; ///< Last move from server
|
||||
F32 dt; ///< Last interpolation time
|
||||
// Interpolation data
|
||||
Point3F pos;
|
||||
Point3F posVec;
|
||||
QuatF rot[2];
|
||||
// Warp data
|
||||
S32 warpTicks; ///< Number of ticks to warp
|
||||
S32 warpCount; ///< Current pos in warp
|
||||
Point3F warpOffset;
|
||||
QuatF warpRot[2];
|
||||
//
|
||||
Point3F cameraOffset;
|
||||
Point3F cameraVec;
|
||||
Point3F cameraRot;
|
||||
Point3F cameraRotVec;
|
||||
};
|
||||
|
||||
StateDelta mDelta;
|
||||
S32 mPredictionCount; ///< Number of ticks to predict
|
||||
VehicleData* mDataBlock;
|
||||
bool inLiquid;
|
||||
SFXSource* mWakeSound;
|
||||
|
||||
Point3F mCameraOffset; ///< 3rd person camera
|
||||
|
||||
// Control
|
||||
Point2F mSteering;
|
||||
F32 mThrottle;
|
||||
bool mJetting;
|
||||
|
||||
// Rigid Body
|
||||
bool mDisableMove;
|
||||
|
||||
GFXStateBlockRef mSolidSB;
|
||||
|
||||
Box3F mWorkingQueryBox;
|
||||
S32 mWorkingQueryBoxCountDown;
|
||||
|
||||
CollisionList mCollisionList;
|
||||
CollisionList mContacts;
|
||||
Rigid mRigid;
|
||||
ShapeBaseConvex mConvex;
|
||||
int restCount;
|
||||
|
||||
SimObjectPtr<ParticleEmitter> mDustEmitterList[VehicleData::VC_NUM_DUST_EMITTERS];
|
||||
SimObjectPtr<ParticleEmitter> mDamageEmitterList[VehicleData::VC_NUM_DAMAGE_EMITTERS];
|
||||
SimObjectPtr<ParticleEmitter> mSplashEmitterList[VehicleData::VC_NUM_SPLASH_EMITTERS];
|
||||
|
||||
//
|
||||
virtual bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
void updatePos(F32 dt);
|
||||
bool updateCollision(F32 dt);
|
||||
bool resolveCollision(Rigid& ns,CollisionList& cList);
|
||||
bool resolveContacts(Rigid& ns,CollisionList& cList,F32 dt);
|
||||
bool resolveDisplacement(Rigid& ns,CollisionState *state,F32 dt);
|
||||
bool findContacts(Rigid& ns,CollisionList& cList);
|
||||
void checkTriggers();
|
||||
static void findCallback(SceneObject* obj,void * key);
|
||||
|
||||
void setPosition(const Point3F& pos,const QuatF& rot);
|
||||
void setRenderPosition(const Point3F& pos,const QuatF& rot);
|
||||
void setTransform(const MatrixF& mat);
|
||||
|
||||
// virtual bool collideBody(const MatrixF& mat,Collision* info) = 0;
|
||||
virtual void updateMove(const Move* move);
|
||||
virtual void updateForces(F32 dt);
|
||||
|
||||
void writePacketData(GameConnection * conn, BitStream *stream);
|
||||
void readPacketData (GameConnection * conn, BitStream *stream);
|
||||
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
|
||||
void updateLiftoffDust( F32 dt );
|
||||
void updateDamageSmoke( F32 dt );
|
||||
|
||||
void updateWorkingCollisionSet(const U32 mask);
|
||||
virtual U32 getCollisionMask();
|
||||
|
||||
void updateFroth( F32 dt );
|
||||
bool collidingWithWater( Point3F &waterHeight );
|
||||
|
||||
/// ObjectRenderInst delegate hooked up in prepBatchRender
|
||||
/// if GameBase::gShowBoundingBox is true.
|
||||
void _renderMassAndContacts( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
|
||||
|
||||
/// ObjectRenderInst delegate hooked up in prepBatchRender
|
||||
/// if GameBase::gShowBoundingBox is true.
|
||||
void _renderMuzzleVector( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
|
||||
|
||||
public:
|
||||
// Test code...
|
||||
static ClippedPolyList* sPolyList;
|
||||
static S32 sVehicleCount;
|
||||
|
||||
//
|
||||
Vehicle();
|
||||
static void consoleInit();
|
||||
static void initPersistFields();
|
||||
void processTick(const Move *move);
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
/// Interpolates between move ticks @see processTick
|
||||
/// @param dt Change in time between the last call and this call to the function
|
||||
void interpolateTick(F32 dt);
|
||||
void advanceTime(F32 dt);
|
||||
|
||||
/// Disables collisions for this vehicle and all mounted objects
|
||||
void disableCollision();
|
||||
|
||||
/// Enables collisions for this vehicle and all mounted objects
|
||||
void enableCollision();
|
||||
|
||||
/// Returns the velocity of the vehicle
|
||||
Point3F getVelocity() const;
|
||||
|
||||
void setEnergyLevel(F32 energy);
|
||||
|
||||
void prepBatchRender( SceneRenderState *state, S32 mountedImageIndex );
|
||||
|
||||
///@name Rigid body methods
|
||||
///@{
|
||||
|
||||
/// This method will get the velocity of the object, taking into account
|
||||
/// angular velocity.
|
||||
/// @param r Point on the object you want the velocity of, relative to Center of Mass
|
||||
/// @param vel Velocity (out)
|
||||
void getVelocity(const Point3F& r, Point3F* vel);
|
||||
|
||||
/// Applies an impulse force
|
||||
/// @param r Point on the object to apply impulse to, r is relative to Center of Mass
|
||||
/// @param impulse Impulse vector to apply.
|
||||
void applyImpulse(const Point3F &r, const Point3F &impulse);
|
||||
|
||||
void getCameraParameters(F32 *min, F32* max, Point3F* offset, MatrixF* rot);
|
||||
void getCameraTransform(F32* pos, MatrixF* mat);
|
||||
///@}
|
||||
|
||||
/// @name Mounted objects
|
||||
/// @{
|
||||
virtual void mountObject( SceneObject *obj, S32 node, const MatrixF &xfm = MatrixF::Identity );
|
||||
/// @}
|
||||
|
||||
DECLARE_CONOBJECT(Vehicle);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
154
Engine/source/T3D/vehicles/vehicleBlocker.cpp
Normal file
154
Engine/source/T3D/vehicles/vehicleBlocker.cpp
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/vehicleBlocker.h"
|
||||
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(VehicleBlocker);
|
||||
|
||||
ConsoleDocClass( VehicleBlocker,
|
||||
"@brief Legacy class from Tribes, originally used for blocking Vehicle objects.\n\n"
|
||||
|
||||
"@note This is no longer useful and should be deprecated soon.\n\n"
|
||||
|
||||
"@internal\n"
|
||||
);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------
|
||||
VehicleBlocker::VehicleBlocker()
|
||||
{
|
||||
mNetFlags.set(Ghostable | ScopeAlways);
|
||||
|
||||
mTypeMask = VehicleBlockerObjectType;
|
||||
|
||||
mConvexList = new Convex;
|
||||
}
|
||||
|
||||
VehicleBlocker::~VehicleBlocker()
|
||||
{
|
||||
delete mConvexList;
|
||||
mConvexList = NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void VehicleBlocker::initPersistFields()
|
||||
{
|
||||
addField("dimensions", TypePoint3F, Offset(mDimensions, VehicleBlocker));
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool VehicleBlocker::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
mObjBox.minExtents.set(-mDimensions.x, -mDimensions.y, 0);
|
||||
mObjBox.maxExtents.set( mDimensions.x, mDimensions.y, mDimensions.z);
|
||||
resetWorldBox();
|
||||
setRenderTransform(mObjToWorld);
|
||||
|
||||
addToScene();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void VehicleBlocker::onRemove()
|
||||
{
|
||||
mConvexList->nukeList();
|
||||
removeFromScene();
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
|
||||
U32 VehicleBlocker::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||
{
|
||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
|
||||
mathWrite(*stream, getTransform());
|
||||
mathWrite(*stream, getScale());
|
||||
mathWrite(*stream, mDimensions);
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
|
||||
void VehicleBlocker::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||
{
|
||||
Parent::unpackUpdate(con, stream);
|
||||
|
||||
MatrixF mat;
|
||||
Point3F scale;
|
||||
Box3F objBox;
|
||||
mathRead(*stream, &mat);
|
||||
mathRead(*stream, &scale);
|
||||
mathRead(*stream, &mDimensions);
|
||||
mObjBox.minExtents.set(-mDimensions.x, -mDimensions.y, 0);
|
||||
mObjBox.maxExtents.set( mDimensions.x, mDimensions.y, mDimensions.z);
|
||||
setScale(scale);
|
||||
setTransform(mat);
|
||||
}
|
||||
|
||||
|
||||
void VehicleBlocker::buildConvex(const Box3F& box, Convex* convex)
|
||||
{
|
||||
// These should really come out of a pool
|
||||
mConvexList->collectGarbage();
|
||||
|
||||
if (box.isOverlapped(getWorldBox()) == false)
|
||||
return;
|
||||
|
||||
// Just return a box convex for the entire shape...
|
||||
Convex* cc = 0;
|
||||
CollisionWorkingList& wl = convex->getWorkingList();
|
||||
for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext)
|
||||
{
|
||||
if (itr->mConvex->getType() == BoxConvexType &&
|
||||
itr->mConvex->getObject() == this) {
|
||||
cc = itr->mConvex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cc)
|
||||
return;
|
||||
|
||||
// Create a new convex.
|
||||
BoxConvex* cp = new BoxConvex;
|
||||
mConvexList->registerObject(cp);
|
||||
convex->addToWorkingList(cp);
|
||||
cp->init(this);
|
||||
|
||||
mObjBox.getCenter(&cp->mCenter);
|
||||
cp->mSize.x = mObjBox.len_x() / 2.0f;
|
||||
cp->mSize.y = mObjBox.len_y() / 2.0f;
|
||||
cp->mSize.z = mObjBox.len_z() / 2.0f;
|
||||
}
|
||||
|
||||
61
Engine/source/T3D/vehicles/vehicleBlocker.h
Normal file
61
Engine/source/T3D/vehicles/vehicleBlocker.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _VEHICLEBLOCKER_H_
|
||||
#define _VEHICLEBLOCKER_H_
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "scene/sceneObject.h"
|
||||
#endif
|
||||
#ifndef _BOXCONVEX_H_
|
||||
#include "collision/boxConvex.h"
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class VehicleBlocker : public SceneObject
|
||||
{
|
||||
typedef SceneObject Parent;
|
||||
friend class VehicleBlockerConvex;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
// Collision
|
||||
void buildConvex(const Box3F& box, Convex* convex);
|
||||
protected:
|
||||
Convex* mConvexList;
|
||||
|
||||
Point3F mDimensions;
|
||||
|
||||
public:
|
||||
VehicleBlocker();
|
||||
~VehicleBlocker();
|
||||
|
||||
DECLARE_CONOBJECT(VehicleBlocker);
|
||||
static void initPersistFields();
|
||||
|
||||
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
};
|
||||
|
||||
#endif // _H_VEHICLEBLOCKER
|
||||
1660
Engine/source/T3D/vehicles/wheeledVehicle.cpp
Normal file
1660
Engine/source/T3D/vehicles/wheeledVehicle.cpp
Normal file
File diff suppressed because it is too large
Load diff
250
Engine/source/T3D/vehicles/wheeledVehicle.h
Normal file
250
Engine/source/T3D/vehicles/wheeledVehicle.h
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _WHEELEDVEHICLE_H_
|
||||
#define _WHEELEDVEHICLE_H_
|
||||
|
||||
#ifndef _VEHICLE_H_
|
||||
#include "T3D/vehicles/vehicle.h"
|
||||
#endif
|
||||
|
||||
#ifndef _CLIPPEDPOLYLIST_H_
|
||||
#include "collision/clippedPolyList.h"
|
||||
#endif
|
||||
|
||||
class ParticleEmitter;
|
||||
class ParticleEmitterData;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
struct WheeledVehicleTire: public SimDataBlock
|
||||
{
|
||||
typedef SimDataBlock Parent;
|
||||
|
||||
//
|
||||
StringTableEntry shapeName;// Max shape to render
|
||||
|
||||
// Physical properties
|
||||
F32 mass; // Mass of the whole wheel
|
||||
F32 kineticFriction; // Tire friction coefficient
|
||||
F32 staticFriction; // Tire friction coefficient
|
||||
F32 restitution; // Currently not used
|
||||
|
||||
// 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.
|
||||
F32 lateralForce; // Spring force
|
||||
F32 lateralDamping; // Damping force
|
||||
F32 lateralRelaxation; // The tire will relax if left alone
|
||||
F32 longitudinalForce;
|
||||
F32 longitudinalDamping;
|
||||
F32 longitudinalRelaxation;
|
||||
|
||||
// Shape information initialized in the preload
|
||||
Resource<TSShape> shape; // The loaded shape
|
||||
F32 radius; // Tire radius
|
||||
|
||||
//
|
||||
WheeledVehicleTire();
|
||||
DECLARE_CONOBJECT(WheeledVehicleTire);
|
||||
static void initPersistFields();
|
||||
bool preload(bool, String &errorStr);
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
struct WheeledVehicleSpring: public SimDataBlock
|
||||
{
|
||||
typedef SimDataBlock Parent;
|
||||
|
||||
F32 length; // Travel distance from root hub position
|
||||
F32 force; // Spring force
|
||||
F32 damping; // Damping force
|
||||
F32 antiSway; // Opposite wheel anti-sway
|
||||
|
||||
//
|
||||
WheeledVehicleSpring();
|
||||
DECLARE_CONOBJECT(WheeledVehicleSpring);
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
struct WheeledVehicleData: public VehicleData
|
||||
{
|
||||
typedef VehicleData Parent;
|
||||
|
||||
enum Constants
|
||||
{
|
||||
MaxWheels = 8,
|
||||
MaxWheelBits = 3
|
||||
};
|
||||
|
||||
enum Sounds
|
||||
{
|
||||
JetSound,
|
||||
EngineSound,
|
||||
SquealSound,
|
||||
WheelImpactSound,
|
||||
MaxSounds,
|
||||
};
|
||||
SFXTrack* sound[MaxSounds];
|
||||
|
||||
ParticleEmitterData* tireEmitter;
|
||||
|
||||
F32 maxWheelSpeed; // Engine torque is scale based on wheel speed
|
||||
F32 engineTorque; // Engine force controlled through throttle
|
||||
F32 engineBrake; // Break force applied when throttle is 0
|
||||
F32 brakeTorque; // Force used when brakeing
|
||||
|
||||
// Initialized onAdd
|
||||
struct Wheel
|
||||
{
|
||||
S32 opposite; // Opposite wheel on Y axis (or -1 for none)
|
||||
Point3F pos; // Root pos of spring
|
||||
S32 springNode; // Wheel spring/hub node
|
||||
S32 springSequence; // Suspension animation
|
||||
F32 springLength; // Suspension animation length
|
||||
} wheel[MaxWheels];
|
||||
U32 wheelCount;
|
||||
ClippedPolyList rigidBody; // Extracted from shape
|
||||
S32 brakeLightSequence; // Brakes
|
||||
S32 steeringSequence; // Steering animation
|
||||
|
||||
//
|
||||
WheeledVehicleData();
|
||||
DECLARE_CONOBJECT(WheeledVehicleData);
|
||||
static void initPersistFields();
|
||||
bool preload(bool, String &errorStr);
|
||||
bool mirrorWheel(Wheel* we);
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class WheeledVehicle: public Vehicle
|
||||
{
|
||||
typedef Vehicle Parent;
|
||||
|
||||
enum MaskBits
|
||||
{
|
||||
WheelMask = Parent::NextFreeMask << 0,
|
||||
NextFreeMask = Parent::NextFreeMask << 1
|
||||
};
|
||||
|
||||
WheeledVehicleData* mDataBlock;
|
||||
|
||||
bool mBraking;
|
||||
TSThread* mTailLightThread;
|
||||
SFXSource* mJetSound;
|
||||
SFXSource* mEngineSound;
|
||||
SFXSource* mSquealSound;
|
||||
|
||||
struct Wheel
|
||||
{
|
||||
WheeledVehicleTire *tire;
|
||||
WheeledVehicleSpring *spring;
|
||||
WheeledVehicleData::Wheel* data;
|
||||
|
||||
F32 extension; // Spring extension (0-1)
|
||||
F32 avel; // Angular velocity
|
||||
F32 apos; // Anuglar position (client side only)
|
||||
F32 Dy,Dx; // Current tire deformation
|
||||
|
||||
struct Surface
|
||||
{
|
||||
bool contact; // Wheel is touching a surface
|
||||
Point3F normal; // Surface normal
|
||||
BaseMatInstance* material; // Surface material
|
||||
Point3F pos; // Point of contact
|
||||
SceneObject* object; // Object in contact with
|
||||
} surface;
|
||||
|
||||
TSShapeInstance* shapeInstance;
|
||||
TSThread* springThread;
|
||||
|
||||
F32 steering; // Wheel steering scale
|
||||
bool powered; // Powered by engine
|
||||
bool slipping; // Traction on last tick
|
||||
F32 torqueScale; // Max torque % applied to wheel (0-1)
|
||||
F32 slip; // Amount of wheel slip (0-1)
|
||||
SimObjectPtr<ParticleEmitter> emitter;
|
||||
};
|
||||
Wheel mWheel[WheeledVehicleData::MaxWheels];
|
||||
TSThread* mSteeringThread;
|
||||
|
||||
//
|
||||
bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
void processTick(const Move *move);
|
||||
void updateMove(const Move *move);
|
||||
void updateForces(F32 dt);
|
||||
void extendWheels(bool clientHack = false);
|
||||
void prepBatchRender( SceneRenderState *state, S32 mountedImageIndex );
|
||||
|
||||
// Client sounds & particles
|
||||
void updateWheelThreads();
|
||||
void updateWheelParticles(F32 dt);
|
||||
void updateEngineSound(F32 level);
|
||||
void updateSquealSound(F32 level);
|
||||
void updateJetSound();
|
||||
|
||||
virtual U32 getCollisionMask();
|
||||
|
||||
public:
|
||||
DECLARE_CONOBJECT(WheeledVehicle);
|
||||
static void initPersistFields();
|
||||
|
||||
WheeledVehicle();
|
||||
~WheeledVehicle();
|
||||
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void advanceTime(F32 dt);
|
||||
bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere);
|
||||
|
||||
S32 getWheelCount();
|
||||
Wheel *getWheel(U32 index) {return &mWheel[index];}
|
||||
void setWheelSteering(S32 wheel,F32 steering);
|
||||
void setWheelPowered(S32 wheel,bool powered);
|
||||
void setWheelTire(S32 wheel,WheeledVehicleTire*);
|
||||
void setWheelSpring(S32 wheel,WheeledVehicleSpring*);
|
||||
|
||||
void getWheelInstAndTransform( U32 wheel, TSShapeInstance** inst, MatrixF* xfrm ) const;
|
||||
|
||||
void writePacketData(GameConnection * conn, BitStream *stream);
|
||||
void readPacketData(GameConnection * conn, BitStream *stream);
|
||||
U32 packUpdate(NetConnection * conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection * conn, BitStream *stream);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue