Game Development Community

dev|Pro Game Development Curriculum

Weapon Charging 2 : Particles

by Owen "WDA" Ashcroft · 07/17/2002 (9:22 am) · 2 comments

Please ensure you have completed the previous tutorial as it builds on that.

All alterations that take place in this tutorial are within the source code itself, if you don't have the source code you will not be able to

implement this as you have to alter the partical engine itself.

The first task is to allow the engine to see the modifier variable. Open crossbow.cs and scroll to the bottom and look for the following

block:
%p = new (%this.projectileType)() {
      dataBlock        = %projectile;
      initialVelocity  = %muzzleVelocity;
      initialPosition  = %obj.getMuzzlePoint(%slot);
      sourceObject     = %obj;
      sourceSlot       = %slot;
      client           = %obj.client;
   };
change it to
%p = new (%this.projectileType)() {
      dataBlock        = %projectile;
      initialVelocity  = %muzzleVelocity;
      initialPosition  = %obj.getMuzzlePoint(%slot);
      sourceObject     = %obj;
      sourceSlot       = %slot;
      client           = %obj.client;
      generalModifier  = %modifier;
   };
This creates another variable called generalModifier that is specific to that particular projectile and with some extra additions will

become visible to the engine itself.

Now fire up the source code, please ensure that your source code compiles by compiling it clean, nothing is worse than thinking that something you

are following is wrong, when in reality there is something wrong with the set up, so just compile it quickly and make sure you get no errors.

Done, good, ok now goto projectile.h now goto line 116 you should see
Point3F  mCurrPosition;
   Point3F  mCurrVelocity;
   S32      mSourceObjectId;
   S32      mSourceObjectSlot;
add the variable S32 mGeneralModifier just underneath that so it looks like
Point3F  mCurrPosition;
   Point3F  mCurrVelocity;
   S32      mSourceObjectId;
   S32      mSourceObjectSlot;
   S32	    mGeneralModifier;
This gives us a variable to put our generalModifier variable from the script into.

Now switch to projectile.cc, goto line 45ish you should see ProjectileData::ProjectileData() anywhere in that section add
generalModifier = 1;
This gives a default value for our scripting variable incase we don't use for a different projectile.

Now goto line 260 to the Projectile::Projectile() section and in there add:
mGeneralModifier = 0;
This again provides a default

value.

Goto line 300 and look for the block of code that looks like:
void Projectile::initPersistFields()
{
   Parent::initPersistFields();

   addField("initialPosition",  TypePoint3F, Offset(mCurrPosition, Projectile));
   addField("initialVelocity", TypePoint3F, Offset(mCurrVelocity, Projectile));
   addField("sourceObject",     TypeS32,     Offset(mSourceObjectId, Projectile));
   addField("sourceSlot",       TypeS32,     Offset(mSourceObjectSlot, Projectile));  
}
add
addField("generalModifier",	TypeS32,	Offset(mGeneralModifier, Projectile));
to the bottom of the addFields, this

puts generalModifier into mGeneralModifier when it comes through from the script.

Next you need to write the mGeneralModifier to the network stream, and conversely include a section so it can be read from it.
Goto line 700 and look for U32 Projectile::packUpdate(NetConnection* con, U32 mask, BitStream* stream) just above return retMask add

stream->write(mGeneralModifier); so the bottom resembles:
stream->write(mGeneralModifier);
   
   return retMask;
This will write the variable to the network stream.
Next you have to add something so it can be read from it. Scroll down about 4 lines and you will see void

Projectile::unpackUpdate(NetConnection* con, BitStream* stream)
at the very bottom (just before the closing bracket) add

stream->read(&mGeneralModifier);.

We still need to make some changes to projectile.cc however we need to add an additional variable to particleEngine.h so load that

up and goto line 135. You should see
void emitParticles(const Point3F& rCenter,
                      const Point3F& rNormal,
                      const F32      radius,
                      const Point3F& velocity,
                      S32 count);
	
   // Internal interface
  protected:
   void addParticle(const Point3F&, const Point3F&, const Point3F&, const Point3F&);
   void renderBillboardParticle( Particle &part, Point3F *basePnts, MatrixF &camView, F32 spinFactor );
make it look like
void emitParticles(const Point3F& rCenter,
                      const Point3F& rNormal,
                      const F32      radius,
                      const Point3F& velocity,
                      S32 count);
	
 
   S32 modifier; //Added variable for modifier.
 
   // Internal interface
  protected:
   void addParticle(const Point3F&, const Point3F&, const Point3F&, const Point3F&);
   void renderBillboardParticle( Particle &part, Point3F *basePnts, MatrixF &camView, F32 spinFactor );
This gives us somewhere to attach our modifier to the particle emitter so the particle engine has access to it.

Return to projectile.cc. Around line 360 you should see the lines:
if (mDataBlock->particleEmitter != NULL)
      {
         ParticleEmitter* pEmitter = new ParticleEmitter;
you need to add a line here so the modifier is transferred to the new ParticleEmitter:
if (mDataBlock->particleEmitter != NULL)
      {
         ParticleEmitter* pEmitter = new ParticleEmitter;
	 pEmitter->modifier = mGeneralModifier; //copies modifier value

That's Projectile.cc[b] finished with, we now turn out attention to [b]ParticleEngine.cc, so load that up.
Goto line 700 you should see the block ParticleEmitter::ParticleEmitter(), you need to add modifier to it so it has a default value, my

code looks like:
ParticleEmitter::ParticleEmitter()
{
   mDeleteWhenEmpty  = false;
   mDeleteOnTick     = false;

   mParticleListHead = NULL;

   mInternalClock    = 0;
   mNextParticleTime = 0;

   mLastPosition.set(0, 0, 0);
   mHasLastPosition = false;

   mLifetimeMS = 0;
   mElapsedTimeMS = 0;

   modifier = 0; //new modifier default value
}
This is to ensure that we always know what the value is and we don't get wacky values.

Next goto line 1470 and look for the lines:
if( emitter.getDataBlock()->useEmitterSizes )
         {
		particle->size = (emitter.sizes[i-1] * (1.0 - firstPart)) +
			         (emitter.sizes[i]   * firstPart);
         }
         else
         {
        	particle->size = (particle->dataBlock->sizes[i-1] * (1.0 - firstPart)) +
                                 (particle->dataBlock->sizes[i]   * firstPart);
         }
This determines the size of the various particles, if needs to look like:
if( emitter.getDataBlock()->useEmitterSizes )
         {
         	if(emitter.modifier != 0)
 	 	{
			particle->size = (emitter.sizes[i-1] * (1.0 - firstPart)) +
				         (emitter.sizes[i]   * firstPart)
					 * emitter.modifier;
		}else{
			particle->size = (emitter.sizes[i-1] * (1.0 - firstPart)) +
				         (emitter.sizes[i]   * firstPart);
		}

         }
         else
         {
            	if(emitter.modifier != 0)
		{
			particle->size = (particle->dataBlock->sizes[i-1] * (1.0 - firstPart)) +
                        	         (particle->dataBlock->sizes[i]   * firstPart)
				         * emitter.modifier;
		}else{
			particle->size = (particle->dataBlock->sizes[i-1] * (1.0 - firstPart)) +
                	                 (particle->dataBlock->sizes[i]   * firstPart);
		}
         }
This will then adjust each particle's size according to its emitters modifier value, as long as that value is not 0.

That should do it, compile the code and charge up the crossbow, if you don't see much change increase to maximum charge from 5 to 25 and just keep

the button held for longer, you should notice a significant size different in the particle effects depending on the length of time the fire button

is held.

#1
07/22/2002 (5:04 am)
This is pretty cool. Seems to work well when I tried it out. I think you need to add this to the projectile.h file though (unless I just didn't see it somehow):
s32 generalModifier;

I did anyway, to make it compile. I put it around line 68 by the explosion stuff. I think that's right. I don't have my code with me at the moment to check.
#2
07/26/2002 (4:59 pm)
Err if it isn't there then yes you do.. Oops. :)