📄 projectile.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "dgl/dgl.h"
#include "sceneGraph/sceneState.h"
#include "sceneGraph/sceneGraph.h"
#include "console/consoleTypes.h"
#include "console/typeValidators.h"
#include "core/bitStream.h"
#include "game/fx/explosion.h"
#include "game/fx/splash.h"
#include "game/shapeBase.h"
#include "ts/tsShapeInstance.h"
#include "game/projectile.h"
#include "audio/audioDataBlock.h"
#include "math/mathUtils.h"
#include "math/mathIO.h"
#include "sim/netConnection.h"
#include "terrain/waterBlock.h"
#include "game/fx/particleEngine.h"
#include "sim/decalManager.h"
IMPLEMENT_CO_DATABLOCK_V1(ProjectileData);
IMPLEMENT_CO_NETOBJECT_V1(Projectile);
const U32 Projectile::csmStaticCollisionMask = TerrainObjectType |
InteriorObjectType |
StaticObjectType;
const U32 Projectile::csmDynamicCollisionMask = PlayerObjectType |
VehicleObjectType |
DamagableItemObjectType;
const U32 Projectile::csmDamageableMask = Projectile::csmDynamicCollisionMask;
U32 Projectile::smProjectileWarpTicks = 5;
//--------------------------------------------------------------------------
//
ProjectileData::ProjectileData()
{
projectileShapeName = NULL;
sound = NULL;
soundId = 0;
explosion = NULL;
explosionId = 0;
waterExplosion = NULL;
waterExplosionId = 0;
splash = NULL;
splashId = 0;
hasLight = false;
lightRadius = 1;
lightColor.set(1, 1, 1);
hasWaterLight = false;
waterLightColor.set(1, 1, 1);
faceViewer = false;
scale.set( 1.0, 1.0, 1.0 );
isBallistic = false;
velInheritFactor = 1.0;
muzzleVelocity = 50;
armingDelay = 0;
fadeDelay = 20000 / 32;
lifetime = 20000 / 32;
activateSeq = -1;
maintainSeq = -1;
gravityMod = 1.0;
bounceElasticity = 0.999;
bounceFriction = 0.3;
particleEmitter = NULL;
particleEmitterId = 0;
particleWaterEmitter = NULL;
particleWaterEmitterId = 0;
decalCount = 0;
for (U32 i = 0; i < NumDecals; i++)
{
decals[i] = NULL;
decalId[i] = 0;
}
}
//--------------------------------------------------------------------------
IMPLEMENT_CONSOLETYPE(ProjectileData)
IMPLEMENT_GETDATATYPE(ProjectileData)
IMPLEMENT_SETDATATYPE(ProjectileData)
void ProjectileData::initPersistFields()
{
Parent::initPersistFields();
addNamedField(particleEmitter, TypeParticleEmitterDataPtr, ProjectileData);
addNamedField(particleWaterEmitter, TypeParticleEmitterDataPtr, ProjectileData);
addNamedField(projectileShapeName, TypeFilename, ProjectileData);
addNamedField(scale, TypePoint3F, ProjectileData);
addNamedField(sound, TypeAudioProfilePtr, ProjectileData);
addNamedField(explosion, TypeExplosionDataPtr, ProjectileData);
addNamedField(waterExplosion, TypeExplosionDataPtr, ProjectileData);
addNamedField(splash, TypeSplashDataPtr, ProjectileData);
addField("decals", TypeDecalDataPtr, Offset(decals, ProjectileData), NumDecals);
addNamedField(hasLight, TypeBool, ProjectileData);
addNamedFieldV(lightRadius, TypeF32, ProjectileData, new FRangeValidator(1, 20));
addNamedField(lightColor, TypeColorF, ProjectileData);
addNamedField(hasWaterLight, TypeBool, ProjectileData);
addNamedField(waterLightColor, TypeColorF, ProjectileData);
addNamedField(isBallistic, TypeBool, ProjectileData);
addNamedFieldV(velInheritFactor, TypeF32, ProjectileData, new FRangeValidator(0, 1));
addNamedFieldV(muzzleVelocity, TypeF32, ProjectileData, new FRangeValidator(0, 10000));
addNamedFieldV(lifetime, TypeS32, ProjectileData, new IRangeValidatorScaled(TickMs, 0, Projectile::MaxLivingTicks));
addNamedFieldV(armingDelay, TypeS32, ProjectileData, new IRangeValidatorScaled(TickMs, 0, Projectile::MaxLivingTicks));
addNamedFieldV(fadeDelay, TypeS32, ProjectileData, new IRangeValidatorScaled(TickMs, 0, Projectile::MaxLivingTicks));
addNamedFieldV(bounceElasticity, TypeF32, ProjectileData, new FRangeValidator(0, 0.999));
addNamedFieldV(bounceFriction, TypeF32, ProjectileData, new FRangeValidator(0, 1));
addNamedFieldV(gravityMod, TypeF32, ProjectileData, new FRangeValidator(0, 1));
}
//--------------------------------------------------------------------------
bool ProjectileData::onAdd()
{
if(!Parent::onAdd())
return false;
if (!particleEmitter && particleEmitterId != 0)
if (Sim::findObject(particleEmitterId, particleEmitter) == false)
Con::errorf(ConsoleLogEntry::General, "ProjectileData::onAdd: Invalid packet, bad datablockId(particleEmitter): %d", particleEmitterId);
if (!particleWaterEmitter && particleWaterEmitterId != 0)
if (Sim::findObject(particleWaterEmitterId, particleWaterEmitter) == false)
Con::errorf(ConsoleLogEntry::General, "ProjectileData::onAdd: Invalid packet, bad datablockId(particleWaterEmitter): %d", particleWaterEmitterId);
if (!explosion && explosionId != 0)
if (Sim::findObject(explosionId, explosion) == false)
Con::errorf(ConsoleLogEntry::General, "ProjectileData::onAdd: Invalid packet, bad datablockId(explosion): %d", explosionId);
if (!waterExplosion && waterExplosionId != 0)
if (Sim::findObject(waterExplosionId, waterExplosion) == false)
Con::errorf(ConsoleLogEntry::General, "ProjectileData::onAdd: Invalid packet, bad datablockId(waterExplosion): %d", waterExplosionId);
if (!splash && splashId != 0)
if (Sim::findObject(splashId, splash) == false)
Con::errorf(ConsoleLogEntry::General, "ProjectileData::onAdd: Invalid packet, bad datablockId(splash): %d", splashId);
if (!sound && soundId != 0)
if (Sim::findObject(soundId, sound) == false)
Con::errorf(ConsoleLogEntry::General, "ProjectileData::onAdd: Invalid packet, bad datablockid(sound): %d", soundId);
lightColor.clamp();
waterLightColor.clamp();
return true;
}
bool ProjectileData::preload(bool server, char errorBuffer[256])
{
if (Parent::preload(server, errorBuffer) == false)
return false;
if (projectileShapeName && projectileShapeName[0] != '\0')
{
projectileShape = ResourceManager->load(projectileShapeName);
if (bool(projectileShape) == false)
{
dSprintf(errorBuffer, sizeof(errorBuffer), "ProjectileData::load: Couldn't load shape \"%s\"", projectileShapeName);
return false;
}
activateSeq = projectileShape->findSequence("activate");
maintainSeq = projectileShape->findSequence("maintain");
}
if (bool(projectileShape)) // create an instance to preload shape data
{
TSShapeInstance* pDummy = new TSShapeInstance(projectileShape, !server);
delete pDummy;
}
// load up all the supplied decal datablocks
// move non-null ones to the front of the array
// for our random decal picker later
U32 i;
DecalData *tmpDecals[NumDecals];
for (i = 0; i < NumDecals; i++)
{
tmpDecals[i] = NULL;
if(!decals[i] && decalId[i] != 0)
if(!Sim::findObject(decalId[i], decals[i]))
Con::errorf( ConsoleLogEntry::General, "ProjectileData::preload Invalid packet, bad datablockId(decals): 0x%x", decalId[i]);
if (!server && decals[i])
{
tmpDecals[decalCount] = decals[i];
decalCount++;
}
}
if (!server && decalCount > 0)
for (i = 0; i < NumDecals; i++)
decals[i] = tmpDecals[i];
return true;
}
//--------------------------------------------------------------------------
void ProjectileData::packData(BitStream* stream)
{
Parent::packData(stream);
stream->writeString(projectileShapeName);
stream->writeFlag(faceViewer);
if(stream->writeFlag(scale.x != 1 || scale.y != 1 || scale.z != 1))
{
stream->write(scale.x);
stream->write(scale.y);
stream->write(scale.z);
}
if (stream->writeFlag(particleEmitter != NULL))
stream->writeRangedU32(particleEmitter->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
if (stream->writeFlag(particleWaterEmitter != NULL))
stream->writeRangedU32(particleWaterEmitter->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
if (stream->writeFlag(explosion != NULL))
stream->writeRangedU32(explosion->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
if (stream->writeFlag(waterExplosion != NULL))
stream->writeRangedU32(waterExplosion->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
if (stream->writeFlag(splash != NULL))
stream->writeRangedU32(splash->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
if (stream->writeFlag(sound != NULL))
stream->writeRangedU32(sound->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
for (U32 i = 0; i < NumDecals; i++)
if (stream->writeFlag(decals[i] != NULL))
stream->writeRangedU32(decals[i]->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
if(stream->writeFlag(hasLight))
{
stream->writeFloat(lightRadius/20.0, 8);
stream->writeFloat(lightColor.red,7);
stream->writeFloat(lightColor.green,7);
stream->writeFloat(lightColor.blue,7);
}
if(stream->writeFlag(hasWaterLight))
{
stream->writeFloat(waterLightColor.red, 7);
stream->writeFloat(waterLightColor.green, 7);
stream->writeFloat(waterLightColor.blue, 7);
}
stream->writeRangedU32(lifetime, 0, Projectile::MaxLivingTicks);
stream->writeRangedU32(armingDelay, 0, Projectile::MaxLivingTicks);
stream->writeRangedU32(fadeDelay, 0, Projectile::MaxLivingTicks);
if(stream->writeFlag(isBallistic))
{
stream->write(gravityMod);
stream->write(bounceElasticity);
stream->write(bounceFriction);
}
// Neither velInheritVelocity nor muzzleVelocity are transmitted to the
// client. This is because in stock Torque, it is not needed for the
// client-side simulation - in general, it is good design to not transmit
// useless information. You could easily add stream->write() calls here,
// and read calls in unpackData, if you did have need of them.
}
void ProjectileData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
projectileShapeName = stream->readSTString();
faceViewer = stream->readFlag();
if(stream->readFlag())
{
stream->read(&scale.x);
stream->read(&scale.y);
stream->read(&scale.z);
}
else
scale.set(1,1,1);
if (stream->readFlag())
particleEmitterId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
if (stream->readFlag())
particleWaterEmitterId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
if (stream->readFlag())
explosionId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
if (stream->readFlag())
waterExplosionId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
if (stream->readFlag())
splashId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
if (stream->readFlag())
soundId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
for (U32 i = 0; i < NumDecals; i++)
if (stream->readFlag())
decalId[i] = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
hasLight = stream->readFlag();
if(hasLight)
{
lightRadius = stream->readFloat(8) * 20;
lightColor.red = stream->readFloat(7);
lightColor.green = stream->readFloat(7);
lightColor.blue = stream->readFloat(7);
}
hasWaterLight = stream->readFlag();
if(hasWaterLight)
{
waterLightColor.red = stream->readFloat(7);
waterLightColor.green = stream->readFloat(7);
waterLightColor.blue = stream->readFloat(7);
}
lifetime = stream->readRangedU32(0, Projectile::MaxLivingTicks);
armingDelay = stream->readRangedU32(0, Projectile::MaxLivingTicks);
fadeDelay = stream->readRangedU32(0, Projectile::MaxLivingTicks);
isBallistic = stream->readFlag();
if(isBallistic)
{
stream->read(&gravityMod);
stream->read(&bounceElasticity);
stream->read(&bounceFriction);
}
}
//--------------------------------------------------------------------------
//--------------------------------------
//
Projectile::Projectile()
{
// Todo: ScopeAlways?
mNetFlags.set(Ghostable);
mTypeMask |= ProjectileObjectType;
mCurrPosition.set(0, 0, 0);
mCurrVelocity.set(0, 0, 1);
mSourceObjectId = -1;
mSourceObjectSlot = -1;
mCurrTick = 0;
mParticleEmitter = NULL;
mParticleWaterEmitter = NULL;
mSoundHandle = NULL_AUDIOHANDLE;
mProjectileShape = NULL;
mActivateThread = NULL;
mMaintainThread = NULL;
mCollideHitType = 0;
mHidden = false;
mFadeValue = 1.0;
}
Projectile::~Projectile()
{
delete mProjectileShape;
mProjectileShape = NULL;
}
//--------------------------------------------------------------------------
void Projectile::initPersistFields()
{
Parent::initPersistFields();
addGroup("Physics");
addField("initialPosition", TypePoint3F, Offset(mCurrPosition, Projectile));
addField("initialVelocity", TypePoint3F, Offset(mCurrVelocity, Projectile));
endGroup("Physics");
addGroup("Source");
addField("sourceObject", TypeS32, Offset(mSourceObjectId, Projectile));
addField("sourceSlot", TypeS32, Offset(mSourceObjectSlot, Projectile));
endGroup("Source");
}
bool Projectile::calculateImpact(float,
Point3F& pointOfImpact,
float& impactTime)
{
Con::warnf(ConsoleLogEntry::General, "Projectile::calculateImpact: Should never be called");
impactTime = 0;
pointOfImpact.set(0, 0, 0);
return false;
}
//--------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -