mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-13 23:54:35 +00:00
Now projectiles wont explode before they have been armed. Results in projectiles being able to collide with several objects before exploding.
This commit is contained in:
parent
66775714ef
commit
9bdeabf22c
1 changed files with 196 additions and 203 deletions
|
|
@ -56,75 +56,75 @@
|
||||||
IMPLEMENT_CO_DATABLOCK_V1(ProjectileData);
|
IMPLEMENT_CO_DATABLOCK_V1(ProjectileData);
|
||||||
|
|
||||||
ConsoleDocClass( ProjectileData,
|
ConsoleDocClass( ProjectileData,
|
||||||
"@brief Stores properties for an individual projectile type.\n"
|
"@brief Stores properties for an individual projectile type.\n"
|
||||||
|
|
||||||
"@tsexample\n"
|
"@tsexample\n"
|
||||||
"datablock ProjectileData(GrenadeLauncherProjectile)\n"
|
"datablock ProjectileData(GrenadeLauncherProjectile)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" projectileShapeName = \"art/shapes/weapons/SwarmGun/rocket.dts\";\n"
|
" projectileShapeName = \"art/shapes/weapons/SwarmGun/rocket.dts\";\n"
|
||||||
"directDamage = 30;\n"
|
"directDamage = 30;\n"
|
||||||
"radiusDamage = 30;\n"
|
"radiusDamage = 30;\n"
|
||||||
"damageRadius = 5;\n"
|
"damageRadius = 5;\n"
|
||||||
"areaImpulse = 2000;\n"
|
"areaImpulse = 2000;\n"
|
||||||
|
|
||||||
"explosion = GrenadeLauncherExplosion;\n"
|
"explosion = GrenadeLauncherExplosion;\n"
|
||||||
"waterExplosion = GrenadeLauncherWaterExplosion;\n"
|
"waterExplosion = GrenadeLauncherWaterExplosion;\n"
|
||||||
|
|
||||||
"decal = ScorchRXDecal;\n"
|
"decal = ScorchRXDecal;\n"
|
||||||
"splash = GrenadeSplash;\n"
|
"splash = GrenadeSplash;\n"
|
||||||
|
|
||||||
"particleEmitter = GrenadeProjSmokeTrailEmitter;\n"
|
"particleEmitter = GrenadeProjSmokeTrailEmitter;\n"
|
||||||
"particleWaterEmitter = GrenadeTrailWaterEmitter;\n"
|
"particleWaterEmitter = GrenadeTrailWaterEmitter;\n"
|
||||||
|
|
||||||
"muzzleVelocity = 30;\n"
|
"muzzleVelocity = 30;\n"
|
||||||
"velInheritFactor = 0.3;\n"
|
"velInheritFactor = 0.3;\n"
|
||||||
|
|
||||||
"armingDelay = 2000;\n"
|
"armingDelay = 2000;\n"
|
||||||
"lifetime = 10000;\n"
|
"lifetime = 10000;\n"
|
||||||
"fadeDelay = 4500;\n"
|
"fadeDelay = 4500;\n"
|
||||||
|
|
||||||
"bounceElasticity = 0.4;\n"
|
"bounceElasticity = 0.4;\n"
|
||||||
"bounceFriction = 0.3;\n"
|
"bounceFriction = 0.3;\n"
|
||||||
"isBallistic = true;\n"
|
"isBallistic = true;\n"
|
||||||
"gravityMod = 0.9;\n"
|
"gravityMod = 0.9;\n"
|
||||||
|
|
||||||
"lightDesc = GrenadeLauncherLightDesc;\n"
|
"lightDesc = GrenadeLauncherLightDesc;\n"
|
||||||
|
|
||||||
"damageType = \"GrenadeDamage\";\n"
|
"damageType = \"GrenadeDamage\";\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"@endtsexample\n"
|
"@endtsexample\n"
|
||||||
|
|
||||||
"@ingroup gameObjects\n"
|
"@ingroup gameObjects\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
IMPLEMENT_CO_NETOBJECT_V1(Projectile);
|
IMPLEMENT_CO_NETOBJECT_V1(Projectile);
|
||||||
|
|
||||||
ConsoleDocClass( Projectile,
|
ConsoleDocClass( Projectile,
|
||||||
"@brief Base projectile class. Uses the ProjectileData class for properties of individual projectiles.\n"
|
"@brief Base projectile class. Uses the ProjectileData class for properties of individual projectiles.\n"
|
||||||
"@ingroup gameObjects\n"
|
"@ingroup gameObjects\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
IMPLEMENT_CALLBACK( ProjectileData, onExplode, void, ( Projectile* proj, Point3F pos, F32 fade ),
|
IMPLEMENT_CALLBACK( ProjectileData, onExplode, void, ( Projectile* proj, Point3F pos, F32 fade ),
|
||||||
( proj, pos, fade ),
|
( proj, pos, fade ),
|
||||||
"@brief Called when a projectile explodes.\n\n"
|
"@brief Called when a projectile explodes.\n\n"
|
||||||
"This function is only called on server objects.\n"
|
"This function is only called on server objects.\n"
|
||||||
"@param proj The exploding projectile.\n"
|
"@param proj The exploding projectile.\n"
|
||||||
"@param pos The position of the explosion.\n"
|
"@param pos The position of the explosion.\n"
|
||||||
"@param fade The current fadeValue of the projectile, affects its visibility.\n\n"
|
"@param fade The current fadeValue of the projectile, affects its visibility.\n\n"
|
||||||
"@see Projectile\n"
|
"@see Projectile\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
IMPLEMENT_CALLBACK( ProjectileData, onCollision, void, ( Projectile* proj, SceneObject* col, F32 fade, Point3F pos, Point3F normal ),
|
IMPLEMENT_CALLBACK( ProjectileData, onCollision, void, ( Projectile* proj, SceneObject* col, F32 fade, Point3F pos, Point3F normal ),
|
||||||
( proj, col, fade, pos, normal ),
|
( proj, col, fade, pos, normal ),
|
||||||
"@brief Called when a projectile collides with another object.\n\n"
|
"@brief Called when a projectile collides with another object.\n\n"
|
||||||
"This function is only called on server objects."
|
"This function is only called on server objects."
|
||||||
"@param proj The projectile colliding with SceneObject col.\n"
|
"@param proj The projectile colliding with SceneObject col.\n"
|
||||||
"@param col The SceneObject hit by the projectile.\n"
|
"@param col The SceneObject hit by the projectile.\n"
|
||||||
"@param fade The current fadeValue of the projectile, affects its visibility.\n"
|
"@param fade The current fadeValue of the projectile, affects its visibility.\n"
|
||||||
"@param pos The position of the collision.\n"
|
"@param pos The position of the collision.\n"
|
||||||
"@param normal The normal of the collision.\n"
|
"@param normal The normal of the collision.\n"
|
||||||
"@see Projectile\n"
|
"@see Projectile\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
const U32 Projectile::csmStaticCollisionMask = TerrainObjectType | StaticShapeObjectType;
|
const U32 Projectile::csmStaticCollisionMask = TerrainObjectType | StaticShapeObjectType;
|
||||||
|
|
||||||
|
|
@ -159,11 +159,11 @@ ProjectileData::ProjectileData()
|
||||||
|
|
||||||
isBallistic = false;
|
isBallistic = false;
|
||||||
|
|
||||||
velInheritFactor = 1.0f;
|
velInheritFactor = 1.0f;
|
||||||
muzzleVelocity = 50;
|
muzzleVelocity = 50;
|
||||||
impactForce = 0.0f;
|
impactForce = 0.0f;
|
||||||
|
|
||||||
armingDelay = 0;
|
armingDelay = 0;
|
||||||
fadeDelay = 20000 / 32;
|
fadeDelay = 20000 / 32;
|
||||||
lifetime = 20000 / 32;
|
lifetime = 20000 / 32;
|
||||||
|
|
||||||
|
|
@ -243,7 +243,7 @@ void ProjectileData::initPersistFields()
|
||||||
"This value is never modified by the engine.\n\n"
|
"This value is never modified by the engine.\n\n"
|
||||||
"@note This value by default is not transmitted between the server and the client.\n\n"
|
"@note This value by default is not transmitted between the server and the client.\n\n"
|
||||||
"@see velInheritFactor");
|
"@see velInheritFactor");
|
||||||
|
|
||||||
addField("impactForce", TypeF32, Offset(impactForce, ProjectileData));
|
addField("impactForce", TypeF32, Offset(impactForce, ProjectileData));
|
||||||
|
|
||||||
addProtectedField("lifetime", TypeS32, Offset(lifetime, ProjectileData), &setLifetime, &getScaledValue,
|
addProtectedField("lifetime", TypeS32, Offset(lifetime, ProjectileData), &setLifetime, &getScaledValue,
|
||||||
|
|
@ -293,7 +293,7 @@ bool ProjectileData::preload(bool server, String &errorStr)
|
||||||
{
|
{
|
||||||
if (Parent::preload(server, errorStr) == false)
|
if (Parent::preload(server, errorStr) == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( !server )
|
if( !server )
|
||||||
{
|
{
|
||||||
if (!particleEmitter && particleEmitterId != 0)
|
if (!particleEmitter && particleEmitterId != 0)
|
||||||
|
|
@ -366,39 +366,39 @@ void ProjectileData::packData(BitStream* stream)
|
||||||
|
|
||||||
if (stream->writeFlag(particleEmitter != NULL))
|
if (stream->writeFlag(particleEmitter != NULL))
|
||||||
stream->writeRangedU32(particleEmitter->getId(), DataBlockObjectIdFirst,
|
stream->writeRangedU32(particleEmitter->getId(), DataBlockObjectIdFirst,
|
||||||
DataBlockObjectIdLast);
|
DataBlockObjectIdLast);
|
||||||
|
|
||||||
if (stream->writeFlag(particleWaterEmitter != NULL))
|
if (stream->writeFlag(particleWaterEmitter != NULL))
|
||||||
stream->writeRangedU32(particleWaterEmitter->getId(), DataBlockObjectIdFirst,
|
stream->writeRangedU32(particleWaterEmitter->getId(), DataBlockObjectIdFirst,
|
||||||
DataBlockObjectIdLast);
|
DataBlockObjectIdLast);
|
||||||
|
|
||||||
if (stream->writeFlag(explosion != NULL))
|
if (stream->writeFlag(explosion != NULL))
|
||||||
stream->writeRangedU32(explosion->getId(), DataBlockObjectIdFirst,
|
stream->writeRangedU32(explosion->getId(), DataBlockObjectIdFirst,
|
||||||
DataBlockObjectIdLast);
|
DataBlockObjectIdLast);
|
||||||
|
|
||||||
if (stream->writeFlag(waterExplosion != NULL))
|
if (stream->writeFlag(waterExplosion != NULL))
|
||||||
stream->writeRangedU32(waterExplosion->getId(), DataBlockObjectIdFirst,
|
stream->writeRangedU32(waterExplosion->getId(), DataBlockObjectIdFirst,
|
||||||
DataBlockObjectIdLast);
|
DataBlockObjectIdLast);
|
||||||
|
|
||||||
if (stream->writeFlag(splash != NULL))
|
if (stream->writeFlag(splash != NULL))
|
||||||
stream->writeRangedU32(splash->getId(), DataBlockObjectIdFirst,
|
stream->writeRangedU32(splash->getId(), DataBlockObjectIdFirst,
|
||||||
DataBlockObjectIdLast);
|
DataBlockObjectIdLast);
|
||||||
|
|
||||||
if (stream->writeFlag(decal != NULL))
|
if (stream->writeFlag(decal != NULL))
|
||||||
stream->writeRangedU32(decal->getId(), DataBlockObjectIdFirst,
|
stream->writeRangedU32(decal->getId(), DataBlockObjectIdFirst,
|
||||||
DataBlockObjectIdLast);
|
DataBlockObjectIdLast);
|
||||||
|
|
||||||
sfxWrite( stream, sound );
|
sfxWrite( stream, sound );
|
||||||
|
|
||||||
if ( stream->writeFlag(lightDesc != NULL))
|
if ( stream->writeFlag(lightDesc != NULL))
|
||||||
stream->writeRangedU32(lightDesc->getId(), DataBlockObjectIdFirst,
|
stream->writeRangedU32(lightDesc->getId(), DataBlockObjectIdFirst,
|
||||||
DataBlockObjectIdLast);
|
DataBlockObjectIdLast);
|
||||||
|
|
||||||
stream->write(impactForce);
|
stream->write(impactForce);
|
||||||
|
|
||||||
// stream->writeRangedU32(lifetime, 0, Projectile::MaxLivingTicks);
|
// stream->writeRangedU32(lifetime, 0, Projectile::MaxLivingTicks);
|
||||||
// stream->writeRangedU32(armingDelay, 0, Projectile::MaxLivingTicks);
|
// stream->writeRangedU32(armingDelay, 0, Projectile::MaxLivingTicks);
|
||||||
// stream->writeRangedU32(fadeDelay, 0, Projectile::MaxLivingTicks);
|
// stream->writeRangedU32(fadeDelay, 0, Projectile::MaxLivingTicks);
|
||||||
|
|
||||||
// [tom, 3/21/2007] Changing these to write all 32 bits as the previous
|
// [tom, 3/21/2007] Changing these to write all 32 bits as the previous
|
||||||
// code limited these to a max value of 4095.
|
// code limited these to a max value of 4095.
|
||||||
|
|
@ -442,22 +442,22 @@ void ProjectileData::unpackData(BitStream* stream)
|
||||||
|
|
||||||
if (stream->readFlag())
|
if (stream->readFlag())
|
||||||
waterExplosionId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
waterExplosionId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||||
|
|
||||||
if (stream->readFlag())
|
if (stream->readFlag())
|
||||||
splashId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
splashId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||||
|
|
||||||
if (stream->readFlag())
|
if (stream->readFlag())
|
||||||
decalId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
decalId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||||
|
|
||||||
sfxRead( stream, &sound );
|
sfxRead( stream, &sound );
|
||||||
|
|
||||||
if (stream->readFlag())
|
if (stream->readFlag())
|
||||||
lightDescId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
lightDescId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||||
|
|
||||||
// [tom, 3/21/2007] See comment in packData()
|
// [tom, 3/21/2007] See comment in packData()
|
||||||
// lifetime = stream->readRangedU32(0, Projectile::MaxLivingTicks);
|
// lifetime = stream->readRangedU32(0, Projectile::MaxLivingTicks);
|
||||||
// armingDelay = stream->readRangedU32(0, Projectile::MaxLivingTicks);
|
// armingDelay = stream->readRangedU32(0, Projectile::MaxLivingTicks);
|
||||||
// fadeDelay = stream->readRangedU32(0, Projectile::MaxLivingTicks);
|
// fadeDelay = stream->readRangedU32(0, Projectile::MaxLivingTicks);
|
||||||
|
|
||||||
stream->read(&impactForce);
|
stream->read(&impactForce);
|
||||||
|
|
||||||
|
|
@ -476,9 +476,9 @@ void ProjectileData::unpackData(BitStream* stream)
|
||||||
|
|
||||||
bool ProjectileData::setLifetime( void *obj, const char *index, const char *data )
|
bool ProjectileData::setLifetime( void *obj, const char *index, const char *data )
|
||||||
{
|
{
|
||||||
S32 value = dAtoi(data);
|
S32 value = dAtoi(data);
|
||||||
value = scaleValue(value);
|
value = scaleValue(value);
|
||||||
|
|
||||||
ProjectileData *object = static_cast<ProjectileData*>(obj);
|
ProjectileData *object = static_cast<ProjectileData*>(obj);
|
||||||
object->lifetime = value;
|
object->lifetime = value;
|
||||||
|
|
||||||
|
|
@ -487,7 +487,7 @@ bool ProjectileData::setLifetime( void *obj, const char *index, const char *data
|
||||||
|
|
||||||
bool ProjectileData::setArmingDelay( void *obj, const char *index, const char *data )
|
bool ProjectileData::setArmingDelay( void *obj, const char *index, const char *data )
|
||||||
{
|
{
|
||||||
S32 value = dAtoi(data);
|
S32 value = dAtoi(data);
|
||||||
value = scaleValue(value);
|
value = scaleValue(value);
|
||||||
|
|
||||||
ProjectileData *object = static_cast<ProjectileData*>(obj);
|
ProjectileData *object = static_cast<ProjectileData*>(obj);
|
||||||
|
|
@ -498,7 +498,7 @@ bool ProjectileData::setArmingDelay( void *obj, const char *index, const char *d
|
||||||
|
|
||||||
bool ProjectileData::setFadeDelay( void *obj, const char *index, const char *data )
|
bool ProjectileData::setFadeDelay( void *obj, const char *index, const char *data )
|
||||||
{
|
{
|
||||||
S32 value = dAtoi(data);
|
S32 value = dAtoi(data);
|
||||||
value = scaleValue(value);
|
value = scaleValue(value);
|
||||||
|
|
||||||
ProjectileData *object = static_cast<ProjectileData*>(obj);
|
ProjectileData *object = static_cast<ProjectileData*>(obj);
|
||||||
|
|
@ -510,7 +510,7 @@ bool ProjectileData::setFadeDelay( void *obj, const char *index, const char *dat
|
||||||
const char *ProjectileData::getScaledValue( void *obj, const char *data)
|
const char *ProjectileData::getScaledValue( void *obj, const char *data)
|
||||||
{
|
{
|
||||||
|
|
||||||
S32 value = dAtoi(data);
|
S32 value = dAtoi(data);
|
||||||
value = scaleValue(value, false);
|
value = scaleValue(value, false);
|
||||||
|
|
||||||
String stringData = String::ToString(value);
|
String stringData = String::ToString(value);
|
||||||
|
|
@ -524,19 +524,19 @@ S32 ProjectileData::scaleValue( S32 value, bool down )
|
||||||
{
|
{
|
||||||
S32 minV = 0;
|
S32 minV = 0;
|
||||||
S32 maxV = Projectile::MaxLivingTicks;
|
S32 maxV = Projectile::MaxLivingTicks;
|
||||||
|
|
||||||
// scale down to ticks before we validate
|
// scale down to ticks before we validate
|
||||||
if( down )
|
if( down )
|
||||||
value /= TickMs;
|
value /= TickMs;
|
||||||
|
|
||||||
if(value < minV || value > maxV)
|
if(value < minV || value > maxV)
|
||||||
{
|
{
|
||||||
Con::errorf("ProjectileData::scaleValue(S32 value = %d, bool down = %b) - Scaled value must be between %d and %d", value, down, minV, maxV);
|
Con::errorf("ProjectileData::scaleValue(S32 value = %d, bool down = %b) - Scaled value must be between %d and %d", value, down, minV, maxV);
|
||||||
if(value < minV)
|
if(value < minV)
|
||||||
value = minV;
|
value = minV;
|
||||||
else if(value > maxV)
|
else if(value > maxV)
|
||||||
value = maxV;
|
value = maxV;
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale up from ticks after we validate
|
// scale up from ticks after we validate
|
||||||
if( !down )
|
if( !down )
|
||||||
|
|
@ -549,7 +549,7 @@ S32 ProjectileData::scaleValue( S32 value, bool down )
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
//
|
//
|
||||||
Projectile::Projectile()
|
Projectile::Projectile()
|
||||||
: mPhysicsWorld( NULL ),
|
: mPhysicsWorld( NULL ),
|
||||||
mCurrPosition( 0, 0, 0 ),
|
mCurrPosition( 0, 0, 0 ),
|
||||||
mCurrVelocity( 0, 0, 1 ),
|
mCurrVelocity( 0, 0, 1 ),
|
||||||
mSourceObjectId( -1 ),
|
mSourceObjectId( -1 ),
|
||||||
|
|
@ -619,12 +619,12 @@ bool Projectile::_setInitialPosition( void *object, const char *index, const cha
|
||||||
Projectile* p = static_cast<Projectile*>( object );
|
Projectile* p = static_cast<Projectile*>( object );
|
||||||
if ( p )
|
if ( p )
|
||||||
{
|
{
|
||||||
Point3F pos;
|
Point3F pos;
|
||||||
|
|
||||||
S32 count = dSscanf( data, "%f %f %f",
|
S32 count = dSscanf( data, "%f %f %f",
|
||||||
&pos.x, &pos.y, &pos.z);
|
&pos.x, &pos.y, &pos.z);
|
||||||
|
|
||||||
if ( (count != 3) )
|
if ( (count != 3) )
|
||||||
{
|
{
|
||||||
Con::printf("Projectile: Failed to parse initial position \"px py pz\" from '%s'", data);
|
Con::printf("Projectile: Failed to parse initial position \"px py pz\" from '%s'", data);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -646,12 +646,12 @@ bool Projectile::_setInitialVelocity( void *object, const char *index, const cha
|
||||||
Projectile* p = static_cast<Projectile*>( object );
|
Projectile* p = static_cast<Projectile*>( object );
|
||||||
if ( p )
|
if ( p )
|
||||||
{
|
{
|
||||||
Point3F vel;
|
Point3F vel;
|
||||||
|
|
||||||
S32 count = dSscanf( data, "%f %f %f",
|
S32 count = dSscanf( data, "%f %f %f",
|
||||||
&vel.x, &vel.y, &vel.z);
|
&vel.x, &vel.y, &vel.z);
|
||||||
|
|
||||||
if ( (count != 3) )
|
if ( (count != 3) )
|
||||||
{
|
{
|
||||||
Con::printf("Projectile: Failed to parse initial velocity \"vx vy vz\" from '%s'", data);
|
Con::printf("Projectile: Failed to parse initial velocity \"vx vy vz\" from '%s'", data);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -826,7 +826,7 @@ void Projectile::submitLights( LightManager *lm, bool staticLighting )
|
||||||
{
|
{
|
||||||
if ( staticLighting || mHasExploded || !mDataBlock->lightDesc )
|
if ( staticLighting || mHasExploded || !mDataBlock->lightDesc )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mDataBlock->lightDesc->submitLight( &mLightState, getRenderTransform(), lm, this );
|
mDataBlock->lightDesc->submitLight( &mLightState, getRenderTransform(), lm, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -834,7 +834,7 @@ bool Projectile::pointInWater(const Point3F &point)
|
||||||
{
|
{
|
||||||
// This is pretty much a hack so we can use the existing ContainerQueryInfo
|
// This is pretty much a hack so we can use the existing ContainerQueryInfo
|
||||||
// and findObject router.
|
// and findObject router.
|
||||||
|
|
||||||
// We only care if we intersect with water at all
|
// We only care if we intersect with water at all
|
||||||
// so build a box at the point that has only 1 z extent.
|
// so build a box at the point that has only 1 z extent.
|
||||||
// And test if water coverage is anything other than zero.
|
// And test if water coverage is anything other than zero.
|
||||||
|
|
@ -845,7 +845,7 @@ bool Projectile::pointInWater(const Point3F &point)
|
||||||
ContainerQueryInfo info;
|
ContainerQueryInfo info;
|
||||||
info.box = boundsBox;
|
info.box = boundsBox;
|
||||||
info.mass = 0.0f;
|
info.mass = 0.0f;
|
||||||
|
|
||||||
// Find and retreive physics info from intersecting WaterObject(s)
|
// Find and retreive physics info from intersecting WaterObject(s)
|
||||||
if(mContainer != NULL)
|
if(mContainer != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -968,7 +968,7 @@ void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideT
|
||||||
mExplosionNormal = n;
|
mExplosionNormal = n;
|
||||||
mCollideHitType = collideType;
|
mCollideHitType = collideType;
|
||||||
|
|
||||||
mDataBlock->onExplode_callback( this, mExplosionPosition, mFadeValue );
|
mDataBlock->onExplode_callback( this, mExplosionPosition, mFadeValue );
|
||||||
|
|
||||||
setMaskBits(ExplosionMask);
|
setMaskBits(ExplosionMask);
|
||||||
|
|
||||||
|
|
@ -987,34 +987,34 @@ void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideT
|
||||||
pExplosion->onNewDataBlock(mDataBlock->waterExplosion, false);
|
pExplosion->onNewDataBlock(mDataBlock->waterExplosion, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (mDataBlock->explosion)
|
if (mDataBlock->explosion)
|
||||||
{
|
|
||||||
pExplosion = new Explosion;
|
|
||||||
pExplosion->onNewDataBlock(mDataBlock->explosion, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( pExplosion )
|
|
||||||
{
|
|
||||||
MatrixF xform(true);
|
|
||||||
xform.setPosition(explodePos);
|
|
||||||
pExplosion->setTransform(xform);
|
|
||||||
pExplosion->setInitialState(explodePos, n);
|
|
||||||
pExplosion->setCollideType( collideType );
|
|
||||||
if (pExplosion->registerObject() == false)
|
|
||||||
{
|
{
|
||||||
Con::errorf(ConsoleLogEntry::General, "Projectile(%s)::explode: couldn't register explosion",
|
pExplosion = new Explosion;
|
||||||
mDataBlock->getName() );
|
pExplosion->onNewDataBlock(mDataBlock->explosion, false);
|
||||||
delete pExplosion;
|
|
||||||
pExplosion = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Client (impact) decal.
|
if( pExplosion )
|
||||||
if ( mDataBlock->decal )
|
{
|
||||||
gDecalManager->addDecal( p, n, 0.0f, mDataBlock->decal );
|
MatrixF xform(true);
|
||||||
|
xform.setPosition(explodePos);
|
||||||
|
pExplosion->setTransform(xform);
|
||||||
|
pExplosion->setInitialState(explodePos, n);
|
||||||
|
pExplosion->setCollideType( collideType );
|
||||||
|
if (pExplosion->registerObject() == false)
|
||||||
|
{
|
||||||
|
Con::errorf(ConsoleLogEntry::General, "Projectile(%s)::explode: couldn't register explosion",
|
||||||
|
mDataBlock->getName() );
|
||||||
|
delete pExplosion;
|
||||||
|
pExplosion = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Client object
|
// Client (impact) decal.
|
||||||
updateSound();
|
if ( mDataBlock->decal )
|
||||||
|
gDecalManager->addDecal( p, n, 0.0f, mDataBlock->decal );
|
||||||
|
|
||||||
|
// Client object
|
||||||
|
updateSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1022,8 +1022,8 @@ void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideT
|
||||||
// within the explosion.
|
// within the explosion.
|
||||||
if ( false && mPhysicsWorld )
|
if ( false && mPhysicsWorld )
|
||||||
{
|
{
|
||||||
F32 force = 200.0f;
|
F32 force = 200.0f;
|
||||||
mPhysicsWorld->explosion( p, 15.0f, force );
|
mPhysicsWorld->explosion( p, 15.0f, force );
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
@ -1063,7 +1063,7 @@ void Projectile::simulate( F32 dt )
|
||||||
deleteObject();
|
deleteObject();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( mHasExploded )
|
if ( mHasExploded )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1106,68 +1106,61 @@ void Projectile::simulate( F32 dt )
|
||||||
if ( isServerObject() && ( rInfo.object->getTypeMask() & csmStaticCollisionMask ) == 0 )
|
if ( isServerObject() && ( rInfo.object->getTypeMask() & csmStaticCollisionMask ) == 0 )
|
||||||
setMaskBits( BounceMask );
|
setMaskBits( BounceMask );
|
||||||
|
|
||||||
|
MatrixF xform( true );
|
||||||
|
xform.setColumn( 3, rInfo.point );
|
||||||
|
setTransform( xform );
|
||||||
|
mCurrPosition = rInfo.point;
|
||||||
|
mCurrVelocity = Point3F::Zero;
|
||||||
|
|
||||||
|
// Get the object type before the onCollision call, in case
|
||||||
|
// the object is destroyed.
|
||||||
|
U32 objectType = rInfo.object->getTypeMask();
|
||||||
|
|
||||||
|
// re-enable the collision response on the source object since
|
||||||
|
// we need to process the onCollision and explode calls
|
||||||
|
if ( disableSourceObjCollision )
|
||||||
|
mSourceObject->enableCollision();
|
||||||
|
|
||||||
|
// Ok, here is how this works:
|
||||||
|
// onCollision is called to notify the server scripts that a collision has occurred, then
|
||||||
|
// a call to explode is made to start the explosion process. The call to explode is made
|
||||||
|
// twice, once on the server and once on the client.
|
||||||
|
// The server process is responsible for two things:
|
||||||
|
// 1) setting the ExplosionMask network bit to guarantee that the client calls explode
|
||||||
|
// 2) initiate the explosion process on the server scripts
|
||||||
|
// The client process is responsible for only one thing:
|
||||||
|
// 1) drawing the appropriate explosion
|
||||||
|
|
||||||
|
// It is possible that during the processTick the server may have decided that a hit
|
||||||
|
// has occurred while the client prediction has decided that a hit has not occurred.
|
||||||
|
// In this particular scenario the client will have failed to call onCollision and
|
||||||
|
// explode during the processTick. However, the explode function will be called
|
||||||
|
// during the next packet update, due to the ExplosionMask network bit being set.
|
||||||
|
// onCollision will remain uncalled on the client however, therefore no client
|
||||||
|
// specific code should be placed inside the function!
|
||||||
|
onCollision( rInfo.point, rInfo.normal, rInfo.object );
|
||||||
// Next order of business: do we explode on this hit?
|
// Next order of business: do we explode on this hit?
|
||||||
if ( mCurrTick > mDataBlock->armingDelay || mDataBlock->armingDelay == 0 )
|
if ( mCurrTick > mDataBlock->armingDelay || mDataBlock->armingDelay == 0 )
|
||||||
{
|
|
||||||
MatrixF xform( true );
|
|
||||||
xform.setColumn( 3, rInfo.point );
|
|
||||||
setTransform( xform );
|
|
||||||
mCurrPosition = rInfo.point;
|
|
||||||
mCurrVelocity = Point3F::Zero;
|
|
||||||
|
|
||||||
// Get the object type before the onCollision call, in case
|
|
||||||
// the object is destroyed.
|
|
||||||
U32 objectType = rInfo.object->getTypeMask();
|
|
||||||
|
|
||||||
// re-enable the collision response on the source object since
|
|
||||||
// we need to process the onCollision and explode calls
|
|
||||||
if ( disableSourceObjCollision )
|
|
||||||
mSourceObject->enableCollision();
|
|
||||||
|
|
||||||
// Ok, here is how this works:
|
|
||||||
// onCollision is called to notify the server scripts that a collision has occurred, then
|
|
||||||
// a call to explode is made to start the explosion process. The call to explode is made
|
|
||||||
// twice, once on the server and once on the client.
|
|
||||||
// The server process is responsible for two things:
|
|
||||||
// 1) setting the ExplosionMask network bit to guarantee that the client calls explode
|
|
||||||
// 2) initiate the explosion process on the server scripts
|
|
||||||
// The client process is responsible for only one thing:
|
|
||||||
// 1) drawing the appropriate explosion
|
|
||||||
|
|
||||||
// It is possible that during the processTick the server may have decided that a hit
|
|
||||||
// has occurred while the client prediction has decided that a hit has not occurred.
|
|
||||||
// In this particular scenario the client will have failed to call onCollision and
|
|
||||||
// explode during the processTick. However, the explode function will be called
|
|
||||||
// during the next packet update, due to the ExplosionMask network bit being set.
|
|
||||||
// onCollision will remain uncalled on the client however, therefore no client
|
|
||||||
// specific code should be placed inside the function!
|
|
||||||
onCollision( rInfo.point, rInfo.normal, rInfo.object );
|
|
||||||
explode( rInfo.point, rInfo.normal, objectType );
|
explode( rInfo.point, rInfo.normal, objectType );
|
||||||
|
|
||||||
// break out of the collision check, since we've exploded
|
if ( mDataBlock->isBallistic )
|
||||||
// we don't want to mess with the position and velocity
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if ( mDataBlock->isBallistic )
|
// Otherwise, this represents a bounce. First, reflect our velocity
|
||||||
{
|
// around the normal...
|
||||||
// Otherwise, this represents a bounce. First, reflect our velocity
|
Point3F bounceVel = mCurrVelocity - rInfo.normal * (mDot( mCurrVelocity, rInfo.normal ) * 2.0);
|
||||||
// around the normal...
|
mCurrVelocity = bounceVel;
|
||||||
Point3F bounceVel = mCurrVelocity - rInfo.normal * (mDot( mCurrVelocity, rInfo.normal ) * 2.0);
|
|
||||||
mCurrVelocity = bounceVel;
|
|
||||||
|
|
||||||
// Add in surface friction...
|
// Add in surface friction...
|
||||||
Point3F tangent = bounceVel - rInfo.normal * mDot(bounceVel, rInfo.normal);
|
Point3F tangent = bounceVel - rInfo.normal * mDot(bounceVel, rInfo.normal);
|
||||||
mCurrVelocity -= tangent * mDataBlock->bounceFriction;
|
mCurrVelocity -= tangent * mDataBlock->bounceFriction;
|
||||||
|
|
||||||
// Now, take elasticity into account for modulating the speed of the grenade
|
// Now, take elasticity into account for modulating the speed of the grenade
|
||||||
mCurrVelocity *= mDataBlock->bounceElasticity;
|
mCurrVelocity *= mDataBlock->bounceElasticity;
|
||||||
|
|
||||||
// Set the new position to the impact and the bounce
|
// Set the new position to the impact and the bounce
|
||||||
// will apply on the next frame.
|
// will apply on the next frame.
|
||||||
//F32 timeLeft = 1.0f - rInfo.t;
|
//F32 timeLeft = 1.0f - rInfo.t;
|
||||||
newPosition = oldPosition = rInfo.point + rInfo.normal * 0.05f;
|
newPosition = oldPosition = rInfo.point + rInfo.normal * 0.05f;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1201,7 +1194,7 @@ void Projectile::advanceTime(F32 dt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mActivateThread &&
|
if (mActivateThread &&
|
||||||
mProjectileShape->getDuration(mActivateThread) > mProjectileShape->getTime(mActivateThread) + dt)
|
mProjectileShape->getDuration(mActivateThread) > mProjectileShape->getTime(mActivateThread) + dt)
|
||||||
{
|
{
|
||||||
mProjectileShape->advanceTime(dt, mActivateThread);
|
mProjectileShape->advanceTime(dt, mActivateThread);
|
||||||
}
|
}
|
||||||
|
|
@ -1237,7 +1230,7 @@ void Projectile::interpolateTick(F32 delta)
|
||||||
dir.normalize();
|
dir.normalize();
|
||||||
|
|
||||||
MatrixF xform(true);
|
MatrixF xform(true);
|
||||||
xform = MathUtils::createOrientFromDir(dir);
|
xform = MathUtils::createOrientFromDir(dir);
|
||||||
xform.setPosition(interpPos);
|
xform.setPosition(interpPos);
|
||||||
setRenderTransform(xform);
|
setRenderTransform(xform);
|
||||||
|
|
||||||
|
|
@ -1265,7 +1258,7 @@ void Projectile::onCollision(const Point3F& hitPosition, const Point3F& hitNorma
|
||||||
|
|
||||||
if (hitObject != NULL && isServerObject())
|
if (hitObject != NULL && isServerObject())
|
||||||
{
|
{
|
||||||
mDataBlock->onCollision_callback( this, hitObject, mFadeValue, hitPosition, hitNormal );
|
mDataBlock->onCollision_callback( this, hitObject, mFadeValue, hitPosition, hitNormal );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1289,12 +1282,12 @@ U32 Projectile::packUpdate( NetConnection *con, U32 mask, BitStream *stream )
|
||||||
if ( stream->writeFlag( ghostIndex != -1 ) )
|
if ( stream->writeFlag( ghostIndex != -1 ) )
|
||||||
{
|
{
|
||||||
stream->writeRangedU32( U32(ghostIndex),
|
stream->writeRangedU32( U32(ghostIndex),
|
||||||
0,
|
0,
|
||||||
NetConnection::MaxGhostCount );
|
NetConnection::MaxGhostCount );
|
||||||
|
|
||||||
stream->writeRangedU32( U32(mSourceObjectSlot),
|
stream->writeRangedU32( U32(mSourceObjectSlot),
|
||||||
0,
|
0,
|
||||||
ShapeBase::MaxMountedImages - 1 );
|
ShapeBase::MaxMountedImages - 1 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// have not recieved the ghost for the source object yet, try again later
|
// have not recieved the ghost for the source object yet, try again later
|
||||||
|
|
@ -1329,7 +1322,7 @@ U32 Projectile::packUpdate( NetConnection *con, U32 mask, BitStream *stream )
|
||||||
void Projectile::unpackUpdate(NetConnection* con, BitStream* stream)
|
void Projectile::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||||
{
|
{
|
||||||
Parent::unpackUpdate(con, stream);
|
Parent::unpackUpdate(con, stream);
|
||||||
|
|
||||||
if ( stream->readFlag() ) // InitialUpdateMask
|
if ( stream->readFlag() ) // InitialUpdateMask
|
||||||
{
|
{
|
||||||
mCurrTick = stream->readRangedU32( 0, MaxLivingTicks );
|
mCurrTick = stream->readRangedU32( 0, MaxLivingTicks );
|
||||||
|
|
@ -1349,7 +1342,7 @@ void Projectile::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||||
mSourceObject = NULL;
|
mSourceObject = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( stream->readFlag() ) // ExplosionMask
|
if ( stream->readFlag() ) // ExplosionMask
|
||||||
{
|
{
|
||||||
Point3F explodePoint;
|
Point3F explodePoint;
|
||||||
|
|
@ -1389,12 +1382,12 @@ void Projectile::prepRenderImage( SceneRenderState* state )
|
||||||
/*
|
/*
|
||||||
if ( mFlareData )
|
if ( mFlareData )
|
||||||
{
|
{
|
||||||
mFlareState.fullBrightness = mDataBlock->lightDesc->mBrightness;
|
mFlareState.fullBrightness = mDataBlock->lightDesc->mBrightness;
|
||||||
mFlareState.scale = mFlareScale;
|
mFlareState.scale = mFlareScale;
|
||||||
mFlareState.lightInfo = mLight;
|
mFlareState.lightInfo = mLight;
|
||||||
mFlareState.lightMat = getTransform();
|
mFlareState.lightMat = getTransform();
|
||||||
|
|
||||||
mFlareData->prepRender( state, &mFlareState );
|
mFlareData->prepRender( state, &mFlareState );
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -1430,18 +1423,18 @@ void Projectile::prepBatchRender( SceneRenderState *state )
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineEngineMethod(Projectile, presimulate, void, (F32 seconds), (1.0f),
|
DefineEngineMethod(Projectile, presimulate, void, (F32 seconds), (1.0f),
|
||||||
"@brief Updates the projectile's positional and collision information.\n\n"
|
"@brief Updates the projectile's positional and collision information.\n\n"
|
||||||
"This function will first delete the projectile if it is a server object and is outside it's ProjectileData::lifetime. "
|
"This function will first delete the projectile if it is a server object and is outside it's ProjectileData::lifetime. "
|
||||||
"Also responsible for applying gravity, determining collisions, triggering explosions, "
|
"Also responsible for applying gravity, determining collisions, triggering explosions, "
|
||||||
"emitting trail particles, and calculating bounces if necessary."
|
"emitting trail particles, and calculating bounces if necessary."
|
||||||
"@param seconds Amount of time, in seconds since the simulation's start, to advance.\n"
|
"@param seconds Amount of time, in seconds since the simulation's start, to advance.\n"
|
||||||
"@tsexample\n"
|
"@tsexample\n"
|
||||||
"// Tell the projectile to process a simulation event, and provide the amount of time\n"
|
"// Tell the projectile to process a simulation event, and provide the amount of time\n"
|
||||||
"// that has passed since the simulation began.\n"
|
"// that has passed since the simulation began.\n"
|
||||||
"%seconds = 2.0;\n"
|
"%seconds = 2.0;\n"
|
||||||
"%projectile.presimulate(%seconds);\n"
|
"%projectile.presimulate(%seconds);\n"
|
||||||
"@endtsexample\n"
|
"@endtsexample\n"
|
||||||
"@note This function is not called if the SimObject::hidden is true.")
|
"@note This function is not called if the SimObject::hidden is true.")
|
||||||
{
|
{
|
||||||
object->simulate( seconds );
|
object->simulate( seconds );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue