Initial commit

This commit is contained in:
Eagle517
2025-02-17 23:17:30 -06:00
commit 7cad314c94
4726 changed files with 1145203 additions and 0 deletions

View File

@ -0,0 +1,736 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "game/vehicles/flyingVehicle.h"
#include "platform/platform.h"
#include "dgl/dgl.h"
#include "game/game.h"
#include "math/mMath.h"
#include "console/simBase.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "collision/clippedPolyList.h"
#include "collision/planeExtractor.h"
#include "game/moveManager.h"
#include "core/bitStream.h"
#include "core/dnet.h"
#include "game/gameConnection.h"
#include "ts/tsShapeInstance.h"
#include "game/fx/particleEngine.h"
#include "audio/audioDataBlock.h"
#include "game/missionArea.h"
//----------------------------------------------------------------------------
const static U32 sCollisionMoveMask = (TerrainObjectType | InteriorObjectType |
WaterObjectType | PlayerObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType | StaticTSObjectType);
static U32 sServerCollisionMask = sCollisionMoveMask; // ItemObjectType
static U32 sClientCollisionMask = sCollisionMoveMask;
static F32 sFlyingVehicleGravity = -20;
// Sound
static F32 sIdleEngineVolume = 0.2;
//
const char* FlyingVehicle::sJetSequence[FlyingVehicle::JetAnimCount] =
{
"activateBack",
"maintainBack",
"activateBot",
"maintainBot",
};
const char* FlyingVehicleData::sJetNode[FlyingVehicleData::MaxJetNodes] =
{
"JetNozzle0", // Thrust Forward
"JetNozzle1",
"JetNozzleX", // Thrust Backward
"JetNozzleX",
"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);
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;
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, char errorBuffer[256])
{
if (!Parent::preload(server, errorBuffer))
return false;
TSShapeInstance* si = new TSShapeInstance(shape,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] = shape->findNode(sJetNode[j]);
//
maxSpeed = maneuveringForce / minDrag;
delete si;
return true;
}
void FlyingVehicleData::initPersistFields()
{
Parent::initPersistFields();
addField("jetSound", TypeAudioProfilePtr, Offset(sound[JetSound], FlyingVehicleData));
addField("engineSound", TypeAudioProfilePtr, Offset(sound[EngineSound], FlyingVehicleData));
addField("maneuveringForce", TypeF32, Offset(maneuveringForce, FlyingVehicleData));
addField("horizontalSurfaceForce", TypeF32, Offset(horizontalSurfaceForce, FlyingVehicleData));
addField("verticalSurfaceForce", TypeF32, Offset(verticalSurfaceForce, FlyingVehicleData));
addField("autoInputDamping", TypeF32, Offset(autoInputDamping, FlyingVehicleData));
addField("steeringForce", TypeF32, Offset(steeringForce, FlyingVehicleData));
addField("steeringRollForce", TypeF32, Offset(steeringRollForce, FlyingVehicleData));
addField("rollForce", TypeF32, Offset(rollForce, FlyingVehicleData));
addField("autoAngularForce", TypeF32, Offset(autoAngularForce, FlyingVehicleData));
addField("rotationalDrag", TypeF32, Offset(rotationalDrag, FlyingVehicleData));
addField("autoLinearForce", TypeF32, Offset(autoLinearForce, FlyingVehicleData));
addField("maxAutoSpeed", TypeF32, Offset(maxAutoSpeed, FlyingVehicleData));
addField("hoverHeight", TypeF32, Offset(hoverHeight, FlyingVehicleData));
addField("createHoverHeight", TypeF32, Offset(createHoverHeight, FlyingVehicleData));
addField("forwardJetEmitter",TypeParticleEmitterDataPtr, Offset(jetEmitter[ForwardJetEmitter], FlyingVehicleData));
addField("backwardJetEmitter",TypeParticleEmitterDataPtr, Offset(jetEmitter[BackwardJetEmitter], FlyingVehicleData));
addField("downJetEmitter",TypeParticleEmitterDataPtr, Offset(jetEmitter[DownwardJetEmitter], FlyingVehicleData));
addField("trailEmitter",TypeParticleEmitterDataPtr, Offset(jetEmitter[TrailEmitter], FlyingVehicleData));
addField("minTrailSpeed", TypeF32, Offset(minTrailSpeed, FlyingVehicleData));
addField("vertThrustMultiple", TypeF32, Offset(vertThrustMultiple, FlyingVehicleData));
}
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] = (AudioProfile*)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);
FlyingVehicle::FlyingVehicle()
{
mGenerateShadow = true;
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()
{
if (mJetSound)
alxStop(mJetSound);
if (mEngineSound)
alxStop(mEngineSound);
}
//----------------------------------------------------------------------------
bool FlyingVehicle::onAdd()
{
if(!Parent::onAdd())
return false;
addToScene();
if (isServerObject())
scriptOnAdd();
return true;
}
bool FlyingVehicle::onNewDataBlock(GameBaseData* dptr)
{
mDataBlock = dynamic_cast<FlyingVehicleData*>(dptr);
if (!mDataBlock || !Parent::onNewDataBlock(dptr))
return false;
// Sounds
if (mJetSound) {
alxStop(mJetSound);
mJetSound = 0;
}
if (mEngineSound) {
alxStop(mEngineSound);
mEngineSound = 0;
}
if (isGhost()) {
if (mDataBlock->sound[FlyingVehicleData::EngineSound])
mEngineSound = alxPlay(mDataBlock->sound[FlyingVehicleData::EngineSound], &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()
{
scriptOnRemove();
removeFromScene();
Parent::onRemove();
}
//----------------------------------------------------------------------------
void FlyingVehicle::advanceTime(F32 dt)
{
Parent::advanceTime(dt);
updateEngineSound(1);
updateJet(dt);
}
//----------------------------------------------------------------------------
void FlyingVehicle::updateMove(const Move* move)
{
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 = dynamic_cast<MissionArea*>(Sim::findObject("MissionArea"));
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;
}
//----------------------------------------------------------------------------
Point3F JetOffset[4] =
{
Point3F(-1,-1,0),
Point3F(+1,-1,0),
Point3F(-1,+1,0),
Point3F(+1,+1,0)
};
void FlyingVehicle::updateForces(F32 /*dt*/)
{
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 * speed * mDot(xv,mRigid.linVelocity) * mDataBlock->horizontalSurfaceForce;
force -= zv * speed * 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;
const F32 height = (createHeightOn) ? mDataBlock->createHoverHeight : mDataBlock->hoverHeight;
const 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, sCollisionMoveMask, &collision))
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) {
alxSourceMatrixF(mEngineSound, &getTransform());
alxSourcef(mEngineSound, AL_GAIN_LINEAR, 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: -1);
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: -1);
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 (!mDataBlock->sound[FlyingVehicleData::JetSound])
return;
if (!mJetting) {
if (mJetSound) {
alxStop(mJetSound);
mJetSound = 0;
}
}
else {
if (!mJetSound)
mJetSound = alxPlay(mDataBlock->sound[FlyingVehicleData::JetSound], &getTransform());
alxSourceMatrixF(mJetSound, &getTransform());
}
}
//----------------------------------------------------------------------------
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);
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(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(getControllingClient() == con)
return;
createHeightOn = stream->readFlag();
mThrustDirection = ThrustDirection(stream->readInt(NumThrustBits));
}
void FlyingVehicle::initPersistFields()
{
Parent::initPersistFields();
}
ConsoleMethod( FlyingVehicle, useCreateHeight, void, 3, 3, "(bool enabled)"
"Should the vehicle temporarily use the create height specified in the datablock? This can help avoid problems with spawning.")
{
object->useCreateHeight(dAtob(argv[2]));
}
void FlyingVehicle::useCreateHeight(bool val)
{
createHeightOn = val;
setMaskBits(HoverHeight);
}

View File

@ -0,0 +1,183 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _FLYINGVEHICLE_H_
#define _FLYINGVEHICLE_H_
#ifndef _VEHICLE_H_
#include "game/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,
};
AudioProfile* 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, char errorBuffer[256]);
void packData(BitStream* stream);
void unpackData(BitStream* stream);
};
//----------------------------------------------------------------------------
class FlyingVehicle: public Vehicle
{
typedef Vehicle Parent;
FlyingVehicleData* mDataBlock;
AUDIOHANDLE mJetSound;
AUDIOHANDLE 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);
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

View File

@ -0,0 +1,123 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "dgl/dgl.h"
#include "gui/controls/guiBitmapCtrl.h"
#include "console/consoleTypes.h"
#include "game/gameConnection.h"
#include "game/vehicles/vehicle.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 it's 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;
public:
GuiSpeedometerHud();
void onRender( Point2I, const RectI &);
static void initPersistFields();
DECLARE_CONOBJECT( GuiSpeedometerHud );
};
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT( GuiSpeedometerHud );
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()
{
Parent::initPersistFields();
addGroup("Needle");
addField("maxSpeed", TypeF32, Offset( mMaxSpeed, GuiSpeedometerHud ) );
addField("minAngle", TypeF32, Offset( mMinAngle, GuiSpeedometerHud ) );
addField("maxAngle", TypeF32, Offset( mMaxAngle, GuiSpeedometerHud ) );
addField("color", TypeColorF, Offset( mColor, GuiSpeedometerHud ) );
addField("center", TypePoint2F, Offset( mCenter, GuiSpeedometerHud ) );
addField("length", TypeF32, Offset( mNeedleLength, GuiSpeedometerHud ) );
addField("width", TypeF32, Offset( mNeedleWidth, GuiSpeedometerHud ) );
addField("tail", TypeF32, Offset( mTailLength, GuiSpeedometerHud ) );
endGroup("Needle");
}
//-----------------------------------------------------------------------------
/**
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 it's speed...
mSpeed = control->getVelocity().len();
if (mSpeed > mMaxSpeed)
mSpeed = mMaxSpeed;
// Render the needle
glPushMatrix();
Point2F center = mCenter;
if (center.x == F32(0) && center.y == F32(0)) {
center.x = mBounds.extent.x / 2;
center.y = mBounds.extent.y / 2;
}
glTranslatef(mBounds.point.x + center.x,mBounds.point.y + center.y,0);
F32 rotation = mMinAngle + (mMaxAngle - mMinAngle) * (mSpeed / mMaxSpeed);
glRotatef(rotation,0.0f,0.0f,-1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glColor4f(mColor.red, mColor.green, mColor.blue, mColor.alpha);
glBegin(GL_LINE_LOOP);
glVertex2f(+mNeedleLength,-mNeedleWidth);
glVertex2f(+mNeedleLength,+mNeedleWidth);
glVertex2f(-mTailLength ,+mNeedleWidth);
glVertex2f(-mTailLength ,-mNeedleWidth);
glEnd();
glPopMatrix();
}

View File

@ -0,0 +1,876 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "game/vehicles/hoverVehicle.h"
#include "core/bitStream.h"
#include "dgl/dgl.h"
#include "sceneGraph/sceneState.h"
#include "collision/clippedPolyList.h"
#include "collision/planeExtractor.h"
#include "game/moveManager.h"
#include "ts/tsShapeInstance.h"
#include "console/consoleTypes.h"
#include "terrain/terrData.h"
#include "sceneGraph/sceneGraph.h"
#include "audio/audioDataBlock.h"
#include "game/fx/particleEngine.h"
#include "math/mathIO.h"
#include "dgl/materialPropertyMap.h"
#include "terrain/waterBlock.h"
IMPLEMENT_CO_DATABLOCK_V1(HoverVehicleData);
IMPLEMENT_CO_NETOBJECT_V1(HoverVehicle);
namespace {
const U32 sIntergrationsPerTick = 1;
const F32 sHoverVehicleGravity = -20;
const U32 sCollisionMoveMask = (TerrainObjectType | InteriorObjectType |
PlayerObjectType | StaticTSObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType);
const U32 sServerCollisionMask = sCollisionMoveMask; // ItemObjectType
const U32 sClientCollisionMask = sCollisionMoveMask;
void nonFilter(SceneObject* object,void *key)
{
Container::CallbackInfo* info = reinterpret_cast<Container::CallbackInfo*>(key);
object->buildPolyList(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.25;
floatingThrustFactor = 0.15;
mainThrustForce = 0;
reverseThrustForce = 0;
strafeThrustForce = 0;
turboFactor = 1.0;
stabLenMin = 0.5;
stabLenMax = 2.0;
stabSpringConstant = 30;
stabDampingConstant = 10;
gyroDrag = 10;
normalForce = 30;
restorativeForce = 10;
steeringForce = 25;
rollForce = 2.5;
pitchForce = 2.5;
dustTrailEmitter = NULL;
dustTrailID = 0;
dustTrailOffset.set( 0.0, 0.0, 0.0 );
dustTrailFreqMod = 15.0;
triggerTrailHeight = 2.5;
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()
{
Parent::initPersistFields();
addField("dragForce", TypeF32, Offset(dragForce, HoverVehicleData));
addField("vertFactor", TypeF32, Offset(vertFactor, HoverVehicleData));
addField("floatingThrustFactor", TypeF32, Offset(floatingThrustFactor, HoverVehicleData));
addField("mainThrustForce", TypeF32, Offset(mainThrustForce, HoverVehicleData));
addField("reverseThrustForce", TypeF32, Offset(reverseThrustForce, HoverVehicleData));
addField("strafeThrustForce", TypeF32, Offset(strafeThrustForce, HoverVehicleData));
addField("turboFactor", TypeF32, Offset(turboFactor, HoverVehicleData));
addField("stabLenMin", TypeF32, Offset(stabLenMin, HoverVehicleData));
addField("stabLenMax", TypeF32, Offset(stabLenMax, HoverVehicleData));
addField("stabSpringConstant", TypeF32, Offset(stabSpringConstant, HoverVehicleData));
addField("stabDampingConstant", TypeF32, Offset(stabDampingConstant, HoverVehicleData));
addField("gyroDrag", TypeF32, Offset(gyroDrag, HoverVehicleData));
addField("normalForce", TypeF32, Offset(normalForce, HoverVehicleData));
addField("restorativeForce", TypeF32, Offset(restorativeForce, HoverVehicleData));
addField("steeringForce", TypeF32, Offset(steeringForce, HoverVehicleData));
addField("rollForce", TypeF32, Offset(rollForce, HoverVehicleData));
addField("pitchForce", TypeF32, Offset(pitchForce, HoverVehicleData));
addField("jetSound", TypeAudioProfilePtr, Offset(sound[JetSound], HoverVehicleData));
addField("engineSound", TypeAudioProfilePtr, Offset(sound[EngineSound], HoverVehicleData));
addField("floatSound", TypeAudioProfilePtr, Offset(sound[FloatSound], HoverVehicleData));
addField("dustTrailEmitter", TypeParticleEmitterDataPtr, Offset(dustTrailEmitter, HoverVehicleData));
addField("dustTrailOffset", TypePoint3F, Offset(dustTrailOffset, HoverVehicleData));
addField("triggerTrailHeight", TypeF32, Offset(triggerTrailHeight, HoverVehicleData));
addField("dustTrailFreqMod", TypeF32, Offset(dustTrailFreqMod, HoverVehicleData));
addField("floatingGravMag", TypeF32, Offset(floatingGravMag, HoverVehicleData));
addField("brakingForce", TypeF32, Offset(brakingForce, HoverVehicleData));
addField("brakingActivationSpeed", TypeF32, Offset(brakingActivationSpeed, HoverVehicleData));
addField("forwardJetEmitter",TypeParticleEmitterDataPtr, Offset(jetEmitter[ForwardJetEmitter], HoverVehicleData));
}
//--------------------------------------------------------------------------
bool HoverVehicleData::onAdd()
{
if(!Parent::onAdd())
return false;
return true;
}
bool HoverVehicleData::preload(bool server, char errorBuffer[256])
{
if (Parent::preload(server, errorBuffer) == 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] = shape->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()?
(AudioProfile*) 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_AUDIOHANDLE;
mEngineSound = NULL_AUDIOHANDLE;
mFloatSound = NULL_AUDIOHANDLE;
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 );
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()
{
scriptOnRemove();
removeFromScene();
if (mJetSound != NULL_AUDIOHANDLE)
alxStop(mJetSound);
if (mEngineSound != NULL_AUDIOHANDLE)
alxStop(mEngineSound);
if (mFloatSound != NULL_AUDIOHANDLE)
alxStop(mFloatSound);
Parent::onRemove();
}
bool HoverVehicle::onNewDataBlock(GameBaseData* dptr)
{
mDataBlock = dynamic_cast<HoverVehicleData*>(dptr);
if (!mDataBlock || !Parent::onNewDataBlock(dptr))
return false;
// Todo: Uncomment if this is a "leaf" class
scriptOnNewDataBlock();
return true;
}
//--------------------------------------------------------------------------
void HoverVehicle::advanceTime(F32 dt)
{
Parent::advanceTime(dt);
// Update jetsound...
if (mJetting) {
if (mJetSound == NULL_AUDIOHANDLE && mDataBlock->sound[HoverVehicleData::JetSound] != NULL)
mJetSound = alxPlay(mDataBlock->sound[HoverVehicleData::JetSound], &getTransform());
if (mJetSound != NULL_AUDIOHANDLE)
alxSourceMatrixF(mJetSound, &getTransform());
} else {
if (mJetSound != NULL_AUDIOHANDLE) {
alxStop(mJetSound);
mJetSound = NULL_AUDIOHANDLE;
}
}
// Update engine sound...
if (mEngineSound == NULL_AUDIOHANDLE && mDataBlock->sound[HoverVehicleData::EngineSound] != NULL)
mEngineSound = alxPlay(mDataBlock->sound[HoverVehicleData::EngineSound], &getTransform());
if (mEngineSound != NULL_AUDIOHANDLE) {
alxSourceMatrixF(mEngineSound, &getTransform());
F32 denom = mDataBlock->mainThrustForce + mDataBlock->strafeThrustForce;
F32 factor = getMin(mThrustLevel, denom) / denom;
F32 vol = 0.25 + factor * 0.75;
alxSourcef(mEngineSound, AL_GAIN_LINEAR, vol);
}
// Are we floating? If so, start the floating sound...
if (mFloating) {
if (mFloatSound == NULL_AUDIOHANDLE && mDataBlock->sound[HoverVehicleData::FloatSound] != NULL)
mFloatSound = alxPlay(mDataBlock->sound[HoverVehicleData::FloatSound], &getTransform());
if (mFloatSound != NULL_AUDIOHANDLE)
alxSourceMatrixF(mFloatSound, &getTransform());
} else {
if (mFloatSound != NULL_AUDIOHANDLE) {
alxStop(mFloatSound);
mFloatSound = NULL_AUDIOHANDLE;
}
}
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;
F32 velRatio = velDiff / mDataBlock->maxThrustSpeed;
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*/)
{
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.min.x + mObjBox.max.x) * 0.5,
mObjBox.max.y,
(mObjBox.min.z + mObjBox.max.z) * 0.5);
stabPoints[1].osPoint = Point3F((mObjBox.min.x + mObjBox.max.x) * 0.5,
mObjBox.min.y,
(mObjBox.min.z + mObjBox.max.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;
}
// Check the waterblock directly
SimpleQueryList sql;
mSceneManager->getWaterObjectList(sql);
for (U32 i = 0; i < sql.mList.size(); i++)
{
WaterBlock* pBlock = static_cast<WaterBlock*>(sql.mList[i]);
if (pBlock->isPointSubmerged(stabPoints[j].wsPoint))
{
compression[j] = baseStabLen;
break;
}
}
}
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 )
{
if( !mDustTrailEmitter ) return;
// check if close to ground
Point3F startPos = getPosition();
Point3F endPos = startPos + Point3F( 0.0, 0.0, -mDataBlock->triggerTrailHeight );
RayInfo rayInfo;
if( !getContainer()->castRay( startPos, endPos, TerrainObjectType, &rayInfo ) )
{
return;
}
VectorF vel = getVelocity();
TerrainBlock* tBlock = static_cast<TerrainBlock*>(rayInfo.object);
S32 mapIndex = tBlock->mMPMIndex[0];
MaterialPropertyMap* pMatMap = static_cast<MaterialPropertyMap*>(Sim::findObject("MaterialPropertyMap"));
const MaterialPropertyMap::MapEntry* pEntry = pMatMap->getMapEntryFromIndex(mapIndex);
// emit dust if moving
if( vel.len() > 2.0 && pEntry)
{
VectorF axis = vel;
axis.normalize();
S32 x;
ColorF colorList[ParticleEngine::PC_COLOR_KEYS];
for(x = 0; x < 2; ++x)
colorList[x].set( pEntry->puffColor[x].red, pEntry->puffColor[x].green, pEntry->puffColor[x].blue, pEntry->puffColor[x].alpha );
for(x = 2; x < ParticleEngine::PC_COLOR_KEYS; ++x)
colorList[x].set( 1.0, 1.0, 1.0, 0.0 );
mDustTrailEmitter->setColors( colorList );
Point3F contactPoint = rayInfo.point + mDataBlock->dustTrailOffset;
mDustTrailEmitter->emitParticles( contactPoint , true, axis, vel, (U32)(dt * 1000 * (vel.len() / mDataBlock->dustTrailFreqMod)));
}
}
void HoverVehicle::updateJet(F32 dt)
{
if (mJetThread[BackActivate] == NULL)
return;
F32 pos = mShapeInstance->getPos(mJetThread[BackActivate]);
F32 scale = mShapeInstance->getTimeScale(mJetThread[BackActivate]);
// 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: -1);
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]);
// 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);
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;
}
}
}

View File

@ -0,0 +1,196 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _HOVERVEHICLE_H_
#define _HOVERVEHICLE_H_
#ifndef _VEHICLE_H_
#include "game/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
};
AudioProfile* 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, char errorBuffer[256]);
DECLARE_CONOBJECT(HoverVehicleData);
static void initPersistFields();
};
// -------------------------------------------------------------------------
class HoverVehicle : public Vehicle
{
typedef Vehicle Parent;
private:
HoverVehicleData* mDataBlock;
ParticleEmitter * mDustTrailEmitter;
protected:
bool onAdd();
void onRemove();
bool onNewDataBlock(GameBaseData *dptr);
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;
AUDIOHANDLE mJetSound;
AUDIOHANDLE mEngineSound;
AUDIOHANDLE 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

1701
engine/game/vehicles/vehicle.cc Executable file

File diff suppressed because it is too large Load Diff

269
engine/game/vehicles/vehicle.h Executable file
View File

@ -0,0 +1,269 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _VEHICLE_H_
#define _VEHICLE_H_
#ifndef _SHAPEBASE_H_
#include "game/shapeBase.h"
#endif
#ifndef _RIGID_H_
#include "game/rigid.h"
#endif
#ifndef _BOXCONVEX_H_
#include "collision/boxConvex.h"
#endif
class ParticleEmitter;
class ParticleEmitterData;
class ClippedPolyList;
//----------------------------------------------------------------------------
struct VehicleData: public ShapeBaseData
{
typedef ShapeBaseData Parent;
struct Body {
enum Sounds {
SoftImpactSound,
HardImpactSound,
MaxSounds,
};
AudioProfile* 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
};
AudioProfile* 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, char errorBuffer[256]);
static void initPersistFields();
virtual void packData(BitStream* stream);
virtual void unpackData(BitStream* stream);
DECLARE_CONOBJECT(VehicleData);
};
//----------------------------------------------------------------------------
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;
AUDIOHANDLE waterWakeHandle;
Point3F mCameraOffset; ///< 3rd person camera
// Control
Point2F mSteering;
F32 mThrottle;
bool mJetting;
// Rigid Body
bool mDisableMove;
CollisionList mCollisionList;
CollisionList mContacts;
Rigid mRigid;
ShapeBaseConvex mConvex;
int restCount;
ParticleEmitter *mDustEmitterList[VehicleData::VC_NUM_DUST_EMITTERS];
ParticleEmitter *mDamageEmitterList[VehicleData::VC_NUM_DAMAGE_EMITTERS];
ParticleEmitter *mSplashEmitterList[VehicleData::VC_NUM_SPLASH_EMITTERS];
//
bool onNewDataBlock(GameBaseData* dptr);
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 );
void renderImage(SceneState *state, SceneRenderImage *image);
void renderMountedImage(SceneState *state, ShapeImageRenderImage *image);
virtual bool getAIMove(Move* move);
public:
// Test code...
static ClippedPolyList* sPolyList;
static S32 sVehicleCount;
//
Vehicle();
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);
///@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);
void mountObject(ShapeBase* obj, U32 node);
///@}
DECLARE_CONOBJECT(Vehicle);
};
#endif

View File

@ -0,0 +1,128 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "game/vehicles/vehicleBlocker.h"
#include "core/bitStream.h"
#include "dgl/dgl.h"
#include "sceneGraph/sceneState.h"
#include "sceneGraph/sceneGraph.h"
#include "math/mathIO.h"
#include "console/consoleTypes.h"
IMPLEMENT_CO_NETOBJECT_V1(VehicleBlocker);
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
VehicleBlocker::VehicleBlocker()
{
mNetFlags.set(Ghostable | ScopeAlways);
mTypeMask = VehicleBlockerObjectType;
mConvexList = new Convex;
}
VehicleBlocker::~VehicleBlocker()
{
delete mConvexList;
mConvexList = NULL;
}
//--------------------------------------------------------------------------
void VehicleBlocker::initPersistFields()
{
Parent::initPersistFields();
addField("dimensions", TypePoint3F, Offset(mDimensions, VehicleBlocker));
}
//--------------------------------------------------------------------------
bool VehicleBlocker::onAdd()
{
if(!Parent::onAdd())
return false;
mObjBox.min.set(-mDimensions.x, -mDimensions.y, 0);
mObjBox.max.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.min.set(-mDimensions.x, -mDimensions.y, 0);
mObjBox.max.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;
}

View File

@ -0,0 +1,44 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _VEHICLEBLOCKER_H_
#define _VEHICLEBLOCKER_H_
#ifndef _SCENEOBJECT_H_
#include "sim/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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,221 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _WHEELEDVEHICLE_H_
#define _WHEELEDVEHICLE_H_
#ifndef _VEHICLE_H_
#include "game/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, char errorBuffer[256]);
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,
};
AudioProfile* 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, char errorBuffer[256]);
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;
AUDIOHANDLE mJetSound;
AUDIOHANDLE mEngineSound;
AUDIOHANDLE 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
U32 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);
void processTick(const Move *move);
void updateMove(const Move *move);
void updateForces(F32 dt);
void renderImage(SceneState *state, SceneRenderImage *image);
void extendWheels(bool clientHack = false);
// Client sounds & particles
void updateWheelThreads();
void updateWheelParticles(F32 dt);
void updateEngineSound(F32 level);
void updateSquealSound(F32 level);
void updateJetSound();
U32 getCollisionMask();
public:
DECLARE_CONOBJECT(WheeledVehicle);
static void initPersistFields();
WheeledVehicle();
~WheeledVehicle();
bool onAdd();
void onRemove();
void advanceTime(F32 dt);
bool buildPolyList(AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere);
S32 getWheelCount();
void setWheelSteering(S32 wheel,F32 steering);
void setWheelPowered(S32 wheel,bool powered);
void setWheelTire(S32 wheel,WheeledVehicleTire*);
void setWheelSpring(S32 wheel,WheeledVehicleSpring*);
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