Game Development Community

Sword on fire

by Matthew Langley · in Torque Game Engine · 12/14/2004 (6:41 am) · 25 replies

What would be the best way to make fire particles spawn on a sword to make it look as though it were on fire...

been scanning through posts and been seeing the complications of this... any advice ?

About the author

Was a GG Associate and then joined GG in 2005. Lead tool dev for T2D and T3D. In 2011 joined mobile company ngmoco/DeNA and spent about 4 years working game and server tech. 2014 joined startup Merigo Games developing server technology.

Page «Previous 1 2
#1
12/14/2004 (6:58 am)
Script, or code?

First, make your sword have some nodes to attach fire to. Then attach particle emitters to those nodes. Best I can think of.

- Brett
#2
12/14/2004 (7:03 am)
I use fire on the sword when the weapon is activated.
I made a stateEmitter on Activate and use a really large StateEmitterTime.
Dont have a spawn function but i should use the reload state or something to spawn the fire.
#3
12/14/2004 (7:14 am)
@Brett: is there a way to attache particle emitters to weapon nodes ?

preferably in script, but I don't mind getting my hands a little dirty in code and adding something a little more efficient and robust. Have tried unscuccesfully to add mounting functions to particles.

@Billy: very cool... stateemitter... how do I spawn the fire... any examples. sorry if I sound a bit stupid, lol trying to figure out particles =/
#4
12/14/2004 (7:21 am)
So if I load a particle emitter on the StateEmitter the particles should initiate on activate (if thats the state I load it into)... and then I can modify a long time...

what about
StateEmitterNode...
know what this is used for..


btw thanks for the help
#5
12/14/2004 (7:23 am)
I dont have a spawn function , the activate state starts the emitter when you mount the weapon.
But this works with the firestate to .
#6
12/14/2004 (7:24 am)
@Brett:


since particle emitter derives from GameBase and not ShapeBase is it still possible to mount a particle Emitter to a weapon node ?

if I'm completely wrong tell me, lol just trying to understand this a little more :)
#7
12/14/2004 (7:31 am)
So something like this should work if I set it up right...


stateName[1] = "Activate";
stateTransitionOnTimeout[1] = "Ready";
stateTimeoutValue[1] = 0.6;
stateSequence[1] = "Activate";
stateEmitter[1] = flameEmitter;
stateEmitterTime[1] = 1000000;


btw time is in ms ?
#8
12/14/2004 (7:45 am)
I did stick a fire emitter on the end of my guys sword. I'm still tweaking stuff, but it mostly works....

First, you need a particle emitter. I stole the spark stuff from crossbow.cs; there are some datablocks named "CrossbowDebrisSparkEmitter" and "CrossbowDebrisSpark" that are a good place to start. I copied these over to my sword.cs and renamed them "SwordSparkEmitter" etc.

Then add some stateEmitterXXX stuff for the states where you want the particle effect to go off. I have the sparks go off whenever the guy attacks with the sword:

data ShapeBaseImage(SwordImage)
{

[...]

stateName[3] = "Fire";
stateFire[3] = true;
[... more stuff for state 3...]
stateEmitter[3] = SwordSparkEmitter;
stateEmitterNode[3] = "DamageStart";
stateEmitterTime[3] = 2000;

[...]

};

The stateEmitterTime is how long the particles occur in milliseconds, but keep in mind that the ParticleEmitterData datablock usually has a "lifetimeMS" parameter that may cut it short. If your particles are not getting displayed long enough, it may by that the "lifetimeMS" stuff in your ParticleEmitterData datablock is really small (100 milliseconds).

Finally, stateEmitterNode tells which node to use. If you don't specify a node, it defaults to the muzzle point (for guns). The 1.3 version of TGE I downloaded seems to have a bug, in that stateEmitterNode is described wrong in initPersistFields (it should be a TypeString instead of TypeS32) but if you build and export the sword model with a muzzle point you don't have to worry about this. I dunno if this is a problem with the copy of HEAD in CVS.
#9
12/14/2004 (8:04 am)
Thanks greatly... explains a lot of what I was thinking...

So a bug in 1.3... currently using version 1.3 myself... any info on if I change it in the source code and compile it will fix it ?


though thanks again, for now I will just use a muzzlepoint
#10
12/14/2004 (8:17 am)
Ok just did

stateEmitter[3] = CrossbowExplosionSmokeEmitter;
stateEmitterTime[3] = 2000;

on the crossbow.. to test it ( on work pc so dont have full objects etc)...

it works the first time, the crossbow muzzlepoint explodes... but beyond the first time nothing happens... is it the particle effect itself that is causing this
#11
12/14/2004 (9:10 am)
For some reason the title of this thread reminded me of:

http://www.stanford.edu/~scodary/tkam.htm
#12
12/14/2004 (12:39 pm)
Thx Pat... that's very silly and quite funny.
#13
12/14/2004 (2:04 pm)
@Matthew
Try a smokeemitter or something then you know its the emitter or not.
Or make a new fire emitter with the particle editor.
#14
12/15/2004 (5:29 am)
Ok got it working, thanks everyone...

it still doesn't re-initiate the particle after I've attacked already, but right now I just increase the lifetime numbers and it works well..


One other thing I've been trying to do is modify the particle code so I can place four emitter nodes in the state system, even if all the nodes point to muzzleNode, then just have each fire effect do different things...


well after a few hours of messing with that (learning a lot about the state / particle system)... I get it to compile, load the new nodes, and if I only load one at a time in the sword.cs then it shows each unique effect; however, if I load them all it just shows the last effect...


so going through the code some more found the

startImageEmitter function...


now this whole time I've done pretty sloppy code, just created three new duplications of most of the node code... at first I was trying to be efficient, but I gave up on that to try and just get it working at all, I can clean the code up after it works...

now I created three new startImageEmitter functions

you pass (image, state) to it...

it errors out on the duplications of this when I use

state.emitter2

or state.emitterNode2... .emitterTime2.. etc

specifically on the

new ParticleEmitter
onNewDatablock()

it compiles, but in runtime when it tries to start all the emitters it exits with ... an error ending with
NOT reentrant

traced that back to a reentrant event... to anyone that might know what I'm running into, is it that I'm duplicating a proccess that adds the event incorrectly... or is it a specific limit to one particleEmitter... the onDatablock part maybe...

was up till 2 am last night trying to get this to work
#15
12/15/2004 (5:33 am)
Heres the call to startImageEmitter

if (isGhost())
      startImageEmitter(image,stateData);

and here is the function

void ShapeBase::startImageEmitter(MountedImage& image,ShapeBaseImageData::StateData& state)
{
   MountedImage::ImageEmitter* bem = 0;
   MountedImage::ImageEmitter* em = image.emitter;
   MountedImage::ImageEmitter* ee = &image.emitter[MaxImageEmitters];

   // If we are already emitting the same particles from the same
   // node, then simply extend the time.  Otherwise, find an empty
   // emitter slot, or grab the one with the least amount of time left.
   for (; em != ee; em++) {
      if (bool(em->emitter)) {
         if (state.emitter == em->emitter->getDataBlock() && state.emitterNode == em->node) {
            if (state.emitterTime > em->time)
               em->time = state.emitterTime;
            return;
         }
         if (!bem || (bool(bem->emitter) && bem->time > em->time))
            bem = em;
      }
      else
         bem = em;
   }

   bem->time = state.emitterTime;
   bem->node = state.emitterNode;
   bem->emitter = new ParticleEmitter;
   bem->emitter->onNewDataBlock(state.emitter);
   bem->emitter->registerObject();
}


here is an example of what I did (very hacky and sloppy i know lol)

the call
startImageEmitterTwo(image,stateData);

the function
void ShapeBase::startImageEmitterTwo(MountedImage& image,ShapeBaseImageData::StateData& state)
{
   MountedImage::ImageEmitter* bem = 0;
   MountedImage::ImageEmitter* em = image.emitter2;
   MountedImage::ImageEmitter* ee = &image.emitter2[MaxImageEmitters];

   // If we are already emitting the same particles from the same
   // node, then simply extend the time.  Otherwise, find an empty
   // emitter slot, or grab the one with the least amount of time left.
   for (; em != ee; em++) {
      if (bool(em->emitter)) {
         if (state.emitter2 == em->emitter->getDataBlock() && state.emitterNode2 == em->node) {
            if (state.emitterTime2 > em->time)
               em->time = state.emitterTime2;
            return;
         }
         if (!bem || (bool(bem->emitter) && bem->time > em->time))
            bem = em;
      }
      else
         bem = em;
   }

   bem->time = state.emitterTime2;
   bem->node = state.emitterNode2;
   bem->emitter = new ParticleEmitter;
   bem->emitter->onNewDataBlock(state.emitter2);
   bem->emitter->registerObject();
}
and again no compile errors, and using one version of this function it works correctly, just only starts one actual node.. the last one loaded I beleive

seems to stall up at

bem->emitter = new ParticleEmitter;
bem->emitter->onNewDataBlock(state.emitter2);
bem->emitter->registerObject();

with "NOT reentrant"...
#16
12/15/2004 (5:33 am)
Why not do the majority of the fire with geometry and texture animation (IFL?) then use an emitter for smoke.
#17
12/15/2004 (5:34 am)
Thanks for the tip, though using blender so exporting is limited

EDIT: plus trying to learn the particle system /state sytem so I can make modifications
#18
12/15/2004 (1:15 pm)
Matthew, I've tried all sorts of code hackery in shapeimage.cc and can't get the "NOT reentrant" jobbers to appear as they did in yours post.

The startImageEmitter can handle up to "MaxImageEmitters" at once, so if you try to create multiple emitters it shouldn't be a problem unless all the emitters use the same emitter node and datablock. Note that MaxImageEmitters is only set to 3 by default, so you may need to crank that up as well.

Also, you can also dump two particles into one emitter I think. Just separate the particle names with a tab. This might be easier than hacking up C++ code.
datablock ParticleEmitterData(SomeEmitter)
{
	ejectionPeriodMS = 15;
	periodVarianceMS = 5;
	ejectionVelocity = 0.25;
	velocityVariance = 0.1;
	thetaMin = 0.0;
	thetaMax = 90.0;
	particles = "SomeAParticle" TAB "SomeBParticle";
};
#19
12/15/2004 (9:26 pm)
Thanks... very very useful... I tried the tab method, works well..

also looked back over my code, seems I missed it in one area...

bool ShapeBaseImageData::preload(bool server, char errorBuffer[256])

my code is pretty hacky... for example

for (U32 i = 0; i < MaxStates; i++) {
         if (state[i].emitter)
            if (!Sim::findObject(SimObjectId(state[i].emitter), state[i].emitter))
               Con::errorf(ConsoleLogEntry::General, "Error, unable to load emitter for image datablock");
         if (state[i].emitter2)
            if (!Sim::findObject(SimObjectId(state[i].emitter2), state[i].emitter2))
               Con::errorf(ConsoleLogEntry::General, "Error, unable to load emitter for image datablock");
		 if (state[i].emitter3)
            if (!Sim::findObject(SimObjectId(state[i].emitter3), state[i].emitter3))
               Con::errorf(ConsoleLogEntry::General, "Error, unable to load emitter for image datablock");
		 if (state[i].emitter4)
            if (!Sim::findObject(SimObjectId(state[i].emitter4), state[i].emitter4))
               Con::errorf(ConsoleLogEntry::General, "Error, unable to load emitter for image datablock");


is there any more efficient way to load multiple emitters such as this... btw with the TAB then I now have the possibility of up to 8 particle effects on a weapon
#20
12/20/2004 (1:27 pm)
That doesn't look very inefficient to me... Just a bunch of object lookups. And datablocks are only init'ed once, so you're not liable to have to need to optimize this stuff, either.
Page «Previous 1 2