Material Based Effects - Appliation - Shapebase vs Shapebase Collisions

From TDN

Shapebase revisited: shapebase.h

Contents

Per material Spark Definitions:

inside struct ShapeBaseData : public GameBaseData {

   ExplosionData* mSpark[MAX_MAT_FX];
   S32 mSparkId[MAX_MAT_FX];

   ParticleEmitterData* SparkEmitter;
   S32 SparkEmitterId;

protected:
   bool onAdd();


inside class ShapeBase : public GameBase
alter:

enum ShapeBaseMasks {
       SparkMask = Parent::NextFreeMask,
	   NameMask        = Parent::NextFreeMask << 1, //change each of these up by 1 till you hit ThreadMaskN     = SoundMaskN  << MaxSoundThreads,

and add:

   SimObjectPtr<ParticleEmitter> mSparkParticleEmitter;
   Point3F mSparkPosition;
   Point3F mSparkNormal;
   U32     mCollideSparkHitType;
   bool mHasCollided;
   SimObjectPtr<ShapeBase> lastHitObject;
   void ShapeBase::processFX();

   /// What to do when this projectile explodes
   virtual void ShapeBase::Spark(const Point3F& p, const Point3F& n, S32 matFxIndex);
   void emitParticles(const Point3F&, const Point3F&, const Point3F&, const U32);
   bool mFadeValue;


again, you'll note the funcname's processFX, to denote were gonna be working with more than just visuals here

shapebase.cc/.cpp

Per material Spark Initialisation:

inside ShapeBaseData::ShapeBaseData()

	for (int i = 0; i<MAX_MAT_FX; i++)
	{
        mSpark[i] = NULL;
        mSparkId[i] = 0;
	}
}

also add:

bool ShapeBaseData::onAdd()
{
   if(!Parent::onAdd())
      return false;

   for (int i = 0; i<MAX_MAT_FX; i++)
	   if (!mSpark[i] && mSparkId[i] != 0)
		   if (Sim::findObject(mSparkId[i], mSpark[i]) == false)
			   Con::errorf(ConsoleLogEntry::General, "ProjectileData::onAdd: Invalid packet, bad datablockId(explosion)[%i]: %d", mSparkId[i],i);
   
   return true;
}

Per material Spark Script-hook:

inside void ShapeBaseData::initPersistFields()

   addField("Sparks", TypeExplosionDataPtr, Offset(mSpark, ShapeBaseData), MAX_MAT_FX);

(yes, I know. explosions. I'll explain that in a sec)


Per material Spark Transmission:

inside void ShapeBaseData::packData(BitStream* stream)

   for (int i=0; i<MAX_MAT_FX; i++)
	   if (stream->writeFlag(mSpark[i] != NULL))
		   stream->writeRangedU32(mSpark[i]->getId(), DataBlockObjectIdFirst,
                                                 DataBlockObjectIdLast);



inside void ShapeBaseData::unpackData(BitStream* stream)

   for (int i = 0; i<MAX_MAT_FX; i++)
       if (stream->readFlag())
		   mSparkId[i] = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);


Per material Spark Support Functionality:

//add
//==============================================================================
//---------------------- Start FX Implementation ------------------------
//==============================================================================
void ShapeBase::Spark(const Point3F& p, const Point3F& n, S32 matFxIndex)
{
   // Make sure we don't explode twice...
   //if (mHidden == true)
      //return;

   //mHidden = true;
   // Client just plays the explosion at the right place...
   //
   Explosion* pSpark = NULL;
   
   F32 waterHeight;
   if (mDataBlock->mSpark[matFxIndex])
   {
	   pSpark = new Explosion;
	   pSpark->onNewDataBlock(mDataBlock->mSpark[matFxIndex]);
   }
   if( pSpark )
   {
	   MatrixF xform(true);
	   xform.setPosition(p);
	   pSpark->setTransform(xform);
	   pSpark->setInitialState(p, n);
	   pSpark->setCollideType( STATIC_COLLISION_MASK );
	   if (pSpark->registerObject() == false)
	   {
		   Con::errorf(ConsoleLogEntry::General, "Projectile(%s)::Spark: couldn't register Spark",
			   mDataBlock->getName() );
		   delete pSpark;
		   pSpark = NULL;
	   }
   }
   // Client object
   //updateSound();
}

void ShapeBase::processFX()
{
	if (!isClientObject()) return;
	this->disableCollision();
	TriRayInfo rInfo; 
	for (CollisionTimeout* ptr = mTimeoutList; ptr; ptr = ptr->next)
	{
		ShapeBase* obj = static_cast<ShapeBase*>(Sim::findObject(ptr->objectNumber)); 
		if (obj != NULL)
		{
			Point3F sp, ep;
			sp = this->getPosition();
			ep = obj->getPosition();
			
			if (obj->castRay(sp, ep, &rInfo))
			{
				Material* matInst = static_cast<Material*>(Sim::findObject(rInfo.material));
				if (matInst != NULL)
				{
					//Con::errorf("Tex: %s", matInst->getName());
					//if (this->mDataBlock->tireEmitter[matInst->mFXIndex] != NULL)
					//{
					Spark(rInfo.point, rInfo.normal,matInst->mFXIndex);
					//Con::errorf("FX: %s", mDataBlock->tireEmitter[matInst->mFXIndex]->getName());
					//}
				}
				//else Con::errorf("matInst Still Registers as (%i)",matInst);
			}
		}
		//else Con::errorf("CollisionTimeout Object (%i) Still Registers as (%i)",ptr->objectNumber, obj);
	}
	//since there's no listing for static objects /interiorinstances in the CollisionTimeout list, we'll just have to
	//do this the brute-force way, till someone brighter throws us a bone
	Point3F sp, ep;
	sp = this->getPosition();
	ep = sp + this->getVelocity()/2;
	if (mContainer->castRay(sp, ep, STATIC_COLLISION_MASK, &rInfo))
	{
		Material* matInst = static_cast<Material*>(Sim::findObject(rInfo.material));
		if (matInst != NULL)
		{
			//Con::errorf("Tex: %s", matInst->getName());
			Spark(rInfo.point, rInfo.normal,matInst->mFXIndex);
		}
		//else Con::errorf("matInst Still Registers as (%i)",matInst);
	}
	this->enableCollision();
}

Per material Spark Usage:

inside void Vehicle::updatePos(F32 dt) after the check

if (isServerObject()) {
...
}

replacing

   else {
      // Play impact sounds on the client.

with

   else {
      notifyCollision();
      // Server side impact script callback
      if (collided) {
         VectorF collVec = mRigid.linVelocity - origVelocity;
         F32 collSpeed = collVec.len();
         if (collSpeed > mDataBlock->minImpactSpeed)
            onImpact(collVec);
      }

      // Play impact sounds on the client.


Sets it up to run the onImpact func on clients as well as servers. Once you have that knocked on out, it's a simple matter of altering

void ShapeBase::onImpact(SceneObject* obj, VectorF vec) to

{
   if (!isGhost()) {
      char buff1[256];
      char buff2[32];

      dSprintf(buff1,sizeof(buff1),"%g %g %g",vec.x, vec.y, vec.z);
      dSprintf(buff2,sizeof(buff2),"%g",vec.len());
      Con::executef(mDataBlock,5,"onImpact",scriptThis(), obj->getIdString(), buff1, buff2);
   }
   else processFX();
}

and

void ShapeBase::onImpact(VectorF vec) to:

{
   if (!isGhost()) {
      char buff1[256];
      char buff2[32];

      dSprintf(buff1,sizeof(buff1),"%g %g %g",vec.x, vec.y, vec.z);
      dSprintf(buff2,sizeof(buff2),"%g",vec.len());
      Con::executef(mDataBlock,5,"onImpact",scriptThis(), "0", buff1, buff2);
   }
   else processFX();
}


Backtrace: Material Based Effects Projects