Created
February 18, 2015 21:01
-
-
Save lukaspj/821e46b3f5aaf6799bc2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "FXProjectile.h" | |
#include "T3D/shapeBase.h" | |
#include "T3D/physics/physicsWorld.h" | |
#include "core/stream/bitStream.h" | |
#include "sim\netConnection.h" | |
#include "math\mathIO.h" | |
IMPLEMENT_CO_DATABLOCK_V1(FXProjectileData); | |
IMPLEMENT_CO_NETOBJECT_V1(FXProjectile); | |
//-------------------------------------------- | |
// FXProjectileData | |
//-------------------------------------------- | |
//-------------------------------------------- | |
// FXProjectile | |
//-------------------------------------------- | |
FXProjectile::FXProjectile() | |
{ | |
mTargetObject = NULL; | |
mHoming = false; | |
mOnlyCollideWithTarget = false; | |
Parent::Projectile(); | |
} | |
//-------------------------------------------- | |
// initPersistFields | |
//-------------------------------------------- | |
void FXProjectile::initPersistFields() | |
{ | |
addGroup("FXProjectile"); | |
addField("TargetObject", TYPEID<SceneObject>(), Offset(mTargetObject, FXProjectile), ""); | |
addField("OnlyCollideWithTarget", TypeBool, Offset(mOnlyCollideWithTarget, FXProjectile), ""); | |
addField("Homing", TypeBool, Offset(mHoming, FXProjectile), ""); | |
addField("InitialTransform", TypeTransformF, Offset(mInitialTransform, FXProjectile), ""); | |
endGroup("FXProjectile"); | |
Parent::initPersistFields(); | |
} | |
//-------------------------------------------- | |
// packUpdate | |
//-------------------------------------------- | |
U32 FXProjectile::packUpdate(NetConnection* conn, U32 mask, BitStream* stream) | |
{ | |
U32 retMask = Parent::packUpdate(conn, mask, stream); | |
if(stream->writeFlag(mask & FXProjectileMask || mask & InitialUpdateMask)) | |
{ | |
S32 ghostID = -1; | |
if(mTargetObject) | |
ghostID = conn->getGhostIndex(mTargetObject); | |
if(stream->writeFlag(ghostID != -1)) | |
stream->writeRangedU32(U32(ghostID), 0, NetConnection::MaxGhostCount); | |
else | |
mTargetObject = NULL; | |
stream->writeFlag(mOnlyCollideWithTarget); | |
stream->writeFlag(mHoming); | |
stream->writeCompressedPoint(mInitialPosition); | |
mathWrite(*stream, mInitialTransform.getMatrix()); | |
} | |
return retMask; | |
} | |
//-------------------------------------------- | |
// unpackUpdate | |
//-------------------------------------------- | |
void FXProjectile::unpackUpdate(NetConnection* conn, BitStream* stream) | |
{ | |
Parent::unpackUpdate(conn, stream); | |
if(stream->readFlag()) | |
{ | |
if(stream->readFlag()) | |
{ | |
S32 TargetID = stream->readRangedU32(0, NetConnection::MaxGhostCount); | |
mTargetObject = (SceneObject*)conn->resolveGhost(TargetID); | |
} | |
else | |
mTargetObject = NULL; | |
mOnlyCollideWithTarget = stream->readFlag(); | |
mHoming = stream->readFlag(); | |
stream->readCompressedPoint(&mInitialPosition); | |
MatrixF mat; | |
mathRead(*stream, &mat); | |
mInitialTransform.set(mat); | |
} | |
} | |
//-------------------------------------------- | |
// processTick | |
//-------------------------------------------- | |
void FXProjectile::processTick( const Move *move ) | |
{ | |
GameBase::processTick( move ); | |
mCurrTick++; | |
simulate( TickSec ); | |
} | |
//-------------------------------------------- | |
// simulate | |
//-------------------------------------------- | |
void FXProjectile::simulate( F32 dt ) | |
{ | |
if ( isServerObject() && mCurrTick >= mDataBlock->lifetime ) | |
{ | |
if(mTargetObject && mOnlyCollideWithTarget && mHoming) | |
{ | |
VectorF normal = -getVelocity(); | |
normal.normalize(); | |
onCollision( getPosition(), normal, mTargetObject ); | |
explode( getPosition(), normal, mTargetObject->getTypeMask() ); | |
} | |
deleteObject(); | |
return; | |
} | |
if ( mHasExploded ) | |
return; | |
// ... otherwise, we have to do some simulation work. | |
RayInfo rInfo; | |
Point3F oldPosition; | |
Point3F newPosition; | |
updatePosition(dt, oldPosition, newPosition); | |
if(!(mTargetObject && mOnlyCollideWithTarget && mHoming)) | |
{ | |
// disable the source objects collision reponse for a short time while we | |
// determine if the projectile is capable of moving from the old position | |
// to the new position, otherwise we'll hit ourself | |
bool disableSourceObjCollision = (mSourceObject.isValid() && mCurrTick <= SourceIdTimeoutTicks); | |
if ( disableSourceObjCollision ) | |
mSourceObject->disableCollision(); | |
disableCollision(); | |
// Determine if the projectile is going to hit any object between the previous | |
// position and the new position. This code is executed both on the server | |
// and on the client (for prediction purposes). It is possible that the server | |
// will have registered a collision while the client prediction has not. If this | |
// happens the client will be corrected in the next packet update. | |
// Raycast the abstract PhysicsWorld if a PhysicsPlugin exists. | |
bool hit = false; | |
if ( mPhysicsWorld ) | |
hit = mPhysicsWorld->castRay( oldPosition, newPosition, &rInfo, Point3F( newPosition - oldPosition) * mDataBlock->impactForce ); | |
else | |
hit = getContainer()->castRay(oldPosition, newPosition, csmDynamicCollisionMask | csmStaticCollisionMask, &rInfo); | |
if ( hit ) | |
{ | |
// make sure the client knows to bounce | |
if ( isServerObject() && ( rInfo.object->getTypeMask() & csmStaticCollisionMask ) == 0 ) | |
setMaskBits( BounceMask ); | |
// Next order of business: do we explode on this hit? | |
if ( mCurrTick > mDataBlock->armingDelay || mDataBlock->armingDelay == 0 ) | |
{ | |
if(!(mTargetObject && mOnlyCollideWithTarget && rInfo.object != mTargetObject) || !mOnlyCollideWithTarget) | |
{ | |
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 ); | |
// break out of the collision check, since we've exploded | |
// 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... | |
Point3F bounceVel = mCurrVelocity - rInfo.normal * (mDot( mCurrVelocity, rInfo.normal ) * 2.0); | |
mCurrVelocity = bounceVel; | |
// Add in surface friction... | |
Point3F tangent = bounceVel - rInfo.normal * mDot(bounceVel, rInfo.normal); | |
mCurrVelocity -= tangent * mDataBlock->bounceFriction; | |
// Now, take elasticity into account for modulating the speed of the grenade | |
mCurrVelocity *= mDataBlock->bounceElasticity; | |
// Set the new position to the impact and the bounce | |
// will apply on the next frame. | |
//F32 timeLeft = 1.0f - rInfo.t; | |
newPosition = oldPosition = rInfo.point + rInfo.normal * 0.05f; | |
} | |
} | |
} | |
// re-enable the collision response on the source object now | |
// that we are done processing the ballistic movement | |
if ( disableSourceObjCollision ) | |
mSourceObject->enableCollision(); | |
enableCollision(); | |
} | |
if ( isClientObject() ) | |
{ | |
emitParticles( mCurrPosition, newPosition, mCurrVelocity, U32( dt * 1000.0f ) ); | |
updateSound(); | |
} | |
mCurrDeltaBase = newPosition; | |
mCurrBackDelta = mCurrPosition - newPosition; | |
mCurrPosition = newPosition; | |
MatrixF xform( true ); | |
xform.setColumn( 3, mCurrPosition ); | |
setTransform( xform ); | |
} | |
void FXProjectile::updatePosition(F32 dt, Point3F &oldPosition, Point3F &newPosition) | |
{ | |
oldPosition = mCurrPosition; | |
if ( mDataBlock->isBallistic ) | |
mCurrVelocity.z -= 9.81 * mDataBlock->gravityMod * dt; | |
if(mHoming && mTargetObject) | |
{ | |
Point3F dir = mTargetObject->getPosition() - oldPosition; | |
dir.normalize(); | |
mCurrVelocity = dir * mCurrVelocity.len(); | |
} | |
newPosition = oldPosition + mCurrVelocity * dt; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef SPELL_PROJECTILE_H | |
#define SPELL_PROJECTILE_H | |
#include "../projectile.h" | |
#include "math\mTransform.h" | |
#include "T3D\shapeBase.h" | |
class FXProjectileData : public ProjectileData | |
{ | |
typedef ProjectileData Parent; | |
public: | |
//------- Enums ------- | |
public: | |
//-------------------------------------------- | |
// SimDataBlock | |
//-------------------------------------------- | |
//-------------------------------------------- | |
// FXProjectileData | |
//-------------------------------------------- | |
//------- Fields ------- | |
DECLARE_CONOBJECT(FXProjectileData); | |
}; | |
class FXProjectile : public Projectile | |
{ | |
typedef Projectile Parent; | |
//------- Enums ------- | |
enum UpdateMasks{ | |
FXProjectileMask = Parent::NextFreeMask << 0 | |
}; | |
public: | |
//-------------------------------------------- | |
// SimObject | |
//-------------------------------------------- | |
static void initPersistFields(); | |
//-------------------------------------------- | |
// GameBase | |
//-------------------------------------------- | |
virtual U32 packUpdate(NetConnection* conn, U32 mask, BitStream* stream); | |
virtual void unpackUpdate(NetConnection* conn, BitStream* stream); | |
//-------------------------------------------- | |
// ITickable | |
//-------------------------------------------- | |
virtual void processTick(const Move *move); | |
//-------------------------------------------- | |
// Projectile | |
//-------------------------------------------- | |
virtual void simulate( F32 dt ); | |
//-------------------------------------------- | |
// FXProjectile | |
//-------------------------------------------- | |
FXProjectile(); | |
//------- Fields ------- | |
bool mHoming; | |
bool mOnlyCollideWithTarget; | |
SceneObject* mTargetObject; | |
TransformF mInitialTransform; | |
void setSourceObject(ShapeBase* obj) { mSourceObject = obj; mSourceObjectId = obj->getId(); }; | |
void setSourceSlot(S32 slot) { mSourceObjectSlot = slot; }; | |
void setHoming(bool homing) { mHoming = homing; }; | |
void setOnlyCollideWithTarget(bool boolean) { mOnlyCollideWithTarget = boolean; }; | |
void setTarget(SceneObject* obj) { mTargetObject = obj; }; | |
void setInitialTransform(MatrixF mat) { mInitialTransform = mat; }; | |
virtual void updatePosition(F32 dt, Point3F &oldPosition, Point3F &newPosition); | |
DECLARE_CONOBJECT(FXProjectile); | |
}; | |
#endif // SPELL_PROJECTILE_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment