LukasPJ Posted February 18, 2015 Share Posted February 18, 2015 Hey guys, this resource adds 2 new Projectile classes that is especially useful for effects.The first is the "FXProjectile" which both adds the OnlyCollideWithTarget and the Homing features. They should be self explanatory. Furthermore this projectile class is more inheritance friendly and makes it easier to add new projectile classes such as the "BezierProjectile" which makes the projectile fly from A to B following a bezier curve.The FXProjectile can be downloaded here.The BezierProjectile can be downloaded here.Example of use: datablock BezierProjectileData(DefaultBezierProjectile) { projectileShapeName = ""; muzzleVelocity = 10; velInheritFactor = 0; armingDelay = 0; particleEmitter = DefaultBezierProjectileEmitter; lifetime = 2000; fadeDelay = 2000; isBallistic = false; bounceElasticity = 0; bounceFriction = 0; gravityMod = 0; hasLight = false; lightRadius = 3; lightColor = "0.8 0.8 1.0"; bezierweights = "15 0 25"; }; function ThrowBezierProjectile(%start, %end, %data, %ignoreCol, %weights) { %vel = VectorSub(%end, %start); %vel = VectorNormalize(%vel); %vel = VectorScale(%vel, %data.muzzleVelocity); %proj = new BezierProjectile() { initialPosition = %start; initialVelocity = %vel; homing = false; BezierWeights = %weights; targetPosition = %end; datablock = %data; }; } And video of that function here (mute it):muGGV2G9XpM Lastly, this old video of mine shows a use case for the projectiles:nveTKVZqBHo Quote Link to comment Share on other sites More sharing options...
Steve_Yorkshire Posted February 19, 2015 Share Posted February 19, 2015 Cool stuff! Also cool music! badapda-da! Quote Link to comment Share on other sites More sharing options...
Gibby Posted February 22, 2015 Share Posted February 22, 2015 @Lucas: Thanks for this! Worked perfectly out of the box! Quote Link to comment Share on other sites More sharing options...
buckmaster Posted February 22, 2015 Share Posted February 22, 2015 Came here to leave this Quote Link to comment Share on other sites More sharing options...
Steve_Yorkshire Posted October 28, 2015 Share Posted October 28, 2015 Noticed a small "jitter" on collision when using FXProjectile with homing, targetObject and onlyCollideWithTarget. Doesn't seem to do anything else, just doesn't delete/vanish on impact. Did look at the code but couldn't see an obvious reason. Quote Link to comment Share on other sites More sharing options...
LukasPJ Posted October 29, 2015 Author Share Posted October 29, 2015 Noticed a small "jitter" on collision when using FXProjectile with homing, targetObject and onlyCollideWithTarget. Doesn't seem to do anything else, just doesn't delete/vanish on impact. Did look at the code but couldn't see an obvious reason.Remind me to look into this over the weekend :P Quote Link to comment Share on other sites More sharing options...
Steve_Yorkshire Posted November 4, 2015 Share Posted November 4, 2015 Had another look at it with a clear head and realised why it's not working.The "onlyCollideWithTarget" var is set to teleport the projectile to the target at the end of it's lifetime and does not actually collide with it ... which is ... er ... odd. Might have been useful for whatever you originally envisioned but ... odd ... for general projectile use. The "onlyCollideWithTarget" var doesn't feature anywhere else except as a negative with collision checking.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; } So I commented that out and put in a positive check for targetObject, OnlyCollideWithTarget and homing vars. Nothing fancy, just working as normies would expect projectile to. So here's what the new simulate function looks like.void FXProjectile::simulate( F32 dt ) { /* //yorks out - why Lucas why!? :P 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(); } else//yorks new down here for testing onlyCollideWithTarget when homing and there is a targetObject { bool disableSourceObjCollision = (mSourceObject.isValid() && mCurrTick <= SourceIdTimeoutTicks); if (disableSourceObjCollision) mSourceObject->disableCollision(); disableCollision(); 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) { 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(); onCollision(rInfo.point, rInfo.normal, rInfo.object); explode(rInfo.point, rInfo.normal, objectType); } } else { if (mDataBlock->isBallistic) { Point3F bounceVel = mCurrVelocity - rInfo.normal * (mDot(mCurrVelocity, rInfo.normal) * 2.0); mCurrVelocity = bounceVel; Point3F tangent = bounceVel - rInfo.normal * mDot(bounceVel, rInfo.normal); mCurrVelocity -= tangent * mDataBlock->bounceFriction; mCurrVelocity *= mDataBlock->bounceElasticity; newPosition = oldPosition = rInfo.point + rInfo.normal * 0.05f; } } } if (disableSourceObjCollision) mSourceObject->enableCollision(); enableCollision(); }//end of yorks 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 ); } And here's a video of some of it in action! :D tog-HlPvBlM Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.