Flaming Sword in TGEA 1.8.1
by Ben McIntosh · 07/05/2009 (12:08 am) · 33 comments
I needed to make a flaming sword for our TGEA 1.8.1 game, so here is how I ended up doing it in the easiest way possible.
Note: I will be using patch notation where lines added are preceded with '+' and lines removed are preceded with a '-'.
First you need to install the Melee Port for TGEA 1.8.1 resource to implement a melee sword weapon.
Next, have you ever tried attaching an emitter to a specific node in a weapon image? You can try with a stateEmitterNode[] definition, but it doesn't work because of a bug that was never fixed, so:
In shapeImage.cpp:
Now, before actually attaching a fire emitter to the sword, it would be much nicer looking if the fire was emitted in a line connecting two nodes in the weapon image. To do this, make the following changes:
In shapeBase.h:
Finally, we need to set up the state machine for the sword. There are a couple of problems that need to be addressed with this.
First, stateEmitter[] is defined on each state, so how can we make a continuous flame that stays lit for all time? Looking through the code for shapeBaseImage, in the startImageEmitter function there is a nice surprise:
Okay, but what if we want to turn the flame on and off at will? You could implement the Setting an ImageState Manually resource, but to me, that looks like a ton of mess for something so simple. I chose to create a third "Ready" state that has no emitter defined. I get to this "Off" state by controlling the sword ammo. Yes, swords have ammo! So when there is ammo, the sword lights up and when there is no ammo, it stops burning. Here is my sword dataBlock:
Just control the ammo to turn the emitter on and off using setInventory(SwordAmmo, 1) or setInventory(SwordAmmo, 0) respectively.
I hope someone finds this useful. :)
Note: I will be using patch notation where lines added are preceded with '+' and lines removed are preceded with a '-'.
First you need to install the Melee Port for TGEA 1.8.1 resource to implement a melee sword weapon.
Next, have you ever tried attaching an emitter to a specific node in a weapon image? You can try with a stateEmitterNode[] definition, but it doesn't work because of a bug that was never fixed, so:
In shapeImage.cpp:
...
void ShapeBaseImageData::initPersistFields()
{
...
addField("stateEmitter", TypeParticleEmitterDataPtr, Offset(stateEmitter, ShapeBaseImageData), MaxStates);
addField("stateEmitterTime", TypeF32, Offset(stateEmitterTime, ShapeBaseImageData), MaxStates);
- addField("stateEmitterNode", TypeS32, Offset(stateEmitterNode, ShapeBaseImageData), MaxStates);
+ addField("stateEmitterNode", TypeString, Offset(stateEmitterNode, ShapeBaseImageData), MaxStates);
...
}
...Wow this bug has been present since at least 2004!Now, before actually attaching a fire emitter to the sword, it would be much nicer looking if the fire was emitted in a line connecting two nodes in the weapon image. To do this, make the following changes:
In shapeBase.h:
...
struct StateData {
...
F32 emitterTime; ///<
S32 emitterNode;
+ S32 emitterNodeEnd;
}
...
/// @name Nodes
/// @{
S32 retractNode; ///< Retraction node ID.
///
/// When the player bumps against an object and the image is retracted to
/// avoid having it interpenetrating the object, it is retracted towards
/// this node.
S32 muzzleNode; ///< Muzzle node ID.
///
///
S32 ejectNode; ///< Ejection node ID.
///
/// The eject node is the node on the image from which shells are ejected.
S32 emitterNode; ///< Emitter node ID.
///
/// The emitter node is the node from which particles are emitted.
+ S32 emitterNodeEnd; ///< Emitter end node ID.
+ ///
+ /// The emitter node end is the node to which particles are emitted from start node.
/// @}
...
struct ImageEmitter {
S32 node;
+ S32 nodeEnd;
F32 time;
SimObjectPtr<ParticleEmitter> emitter;
};
...Again back to shapeImage.cpp:...
bool ShapeBaseImageData::onAdd()
{
...
s.emitter = stateEmitter[i];
s.emitterTime = stateEmitterTime[i];
s.emitterNode = -1; // resolved in load
+ s.emitterNodeEnd = -1; // resolved in load
...
}
...
bool ShapeBaseImageData::preload(bool server, String &errorStr)
{
...
if (stateEmitterNode[i] && stateEmitterNode[i][0])
+ {
+ char buff1[32];
+ char buff2[32];
+ dSprintf(buff1,sizeof(buff1),"%sStart",stateEmitterNode[i]);
+ dSprintf(buff2,sizeof(buff2),"%sEnd",stateEmitterNode[i]);
- s.emitterNode = shape->findNode(stateEmitterNode[i]);
+ s.emitterNode = shape->findNode(buff1);
+ s.emitterNodeEnd = shape->findNode(buff2);
+ }
if (s.emitterNode == -1)
+ {
s.emitterNode = muzzleNode;
+ s.emitterNodeEnd = muzzleNode;
+ }
...
}
...
void ShapeBase::updateImageAnimation(U32 imageSlot, F32 dt)
{
...
// Particle emission
for (S32 i = 0; i < MaxImageEmitters; i++) {
MountedImage::ImageEmitter& em = image.emitter[i];
if (bool(em.emitter)) {
if (em.time > 0) {
em.time -= dt;
MatrixF mat;
+ MatrixF matEnd;
getRenderImageTransform(imageSlot,em.node,&mat);
+ getRenderImageTransform(imageSlot,em.nodeEnd,&matEnd);
Point3F pos,axis;
+ Point3F posEnd,axisEnd;
mat.getColumn(3,&pos);
mat.getColumn(1,&axis);
+ matEnd.getColumn(3,&posEnd);
+ matEnd.getColumn(1,&axisEnd);
- em.emitter->emitParticles(pos,true,axis,getVelocity(),(U32) (dt * 1000));
+ em.emitter->emitParticles(pos,posEnd,axis,getVelocity(),(U32) (dt * 1000));
}
else {
em.emitter->deleteWhenEmpty();
em.emitter = 0;
}
}
}
}
...
void ShapeBase::startImageEmitter(MountedImage& image,ShapeBaseImageData::StateData& state)
{
...
bem->time = state.emitterTime;
bem->node = state.emitterNode;
+ bem->nodeEnd = state.emitterNodeEnd;
bem->emitter = new ParticleEmitter;
bem->emitter->onNewDataBlock(state.emitter);
if( !bem->emitter->registerObject() )
delete bem->emitter;
}
...Now, to use the new code, you simply need to have a node defined in your weapon where you want the emitter to start (e.g. fireStart) and a node where you want the emitter to end (e.g. fireEnd). These two nodes must end with "Start" and "End" respectively. The stateEmitterNode[] should be set to the first part of the name of both nodes, in this case "fire". If you are using the Melee resource, then using "damage" will work out of the box because the included sword DTS model contains "damageStart" and "damageEnd".Finally, we need to set up the state machine for the sword. There are a couple of problems that need to be addressed with this.
First, stateEmitter[] is defined on each state, so how can we make a continuous flame that stays lit for all time? Looking through the code for shapeBaseImage, in the startImageEmitter function there is a nice surprise:
// 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.Great, so if we define the same emitter on the same node for all states, we should get a continuous flame with no problems. But what if we are in one state for too long? We can set the stateEmitterTime[] to a very high number, but that seems a little messy. Instead, I chose to create two "Ready" states that circulate between each other and continually refresh the flame emitter (you need two states because you cannot loop a state back to itself).
Okay, but what if we want to turn the flame on and off at will? You could implement the Setting an ImageState Manually resource, but to me, that looks like a ton of mess for something so simple. I chose to create a third "Ready" state that has no emitter defined. I get to this "Off" state by controlling the sword ammo. Yes, swords have ammo! So when there is ammo, the sword lights up and when there is no ammo, it stops burning. Here is my sword dataBlock:
datablock ShapeBaseImageData(SwordImage)
{
shapeFile = "~/data/shapes/weapons/sword/rune_blade01.dts";
emap = true;
mountPoint = 0;
correctMuzzleVector = false;
className = "WeaponImage";
item = Sword;
ammo = SwordAmmo;
customLookAnim = "looknw";
// Here are the Attacks we support
hthNumAttacks = 3;
hthAttack[0] = OneHandedAttackSwing;
hthAttack[1] = OneHandedAttackSlice;
hthAttack[2] = OneHandedAttackThrust;
// Initial start up state
stateName[0] = "Preactivate";
stateTransitionOnLoaded[0] = "Activate";
// Activating the sword. Called when the weapon is first mounted
stateName[1] = "Activate";
stateTransitionOnTimeout[1] = "ReadyEmitterOn1";
stateTimeoutValue[1] = 0.6;
//stateSequence[1] = "Activate";
// Ready to fire, just waiting for the trigger, emitter on
stateName[2] = "ReadyEmitterOn1";
stateTransitionOnNoAmmo[2] = "ReadyEmitterOff";
stateTransitionOnTriggerDown[2] = "Fire";
stateTransitionOnTimeout[2] = "ReadyEmitterOn2";
stateTimeoutValue[2] = 1;
stateWaitForTimeout[2] = false;
stateEmitter[2] = "TorchFireEmitter";
stateEmitterTime[2] = 1;
stateEmitterNode[2] = "damage";
// Ready to fire, just waiting for the trigger, emitter on
stateName[3] = "ReadyEmitterOn2";
stateTransitionOnNoAmmo[3] = "ReadyEmitterOff";
stateTransitionOnTriggerDown[3] = "Fire";
stateTransitionOnTimeout[3] = "ReadyEmitterOn1";
stateTimeoutValue[3] = 1;
stateWaitForTimeout[3] = false;
stateEmitter[3] = "TorchFireEmitter";
stateEmitterTime[3] = 1;
stateEmitterNode[3] = "damage";
// Ready to fire, just waiting for the trigger, emitter off
stateName[4] = "ReadyEmitterOff";
stateTransitionOnAmmo[4] = "ReadyEmitterOn1";
stateTransitionOnTriggerDown[4] = "Fire";
// Fire the weapon. Calls the fire script which does the actual work.
stateName[5] = "Fire";
stateTransitionOnTimeout[5] = "Reload";
stateTimeoutValue[5] = 0.2;
stateFire[5] = true;
stateAllowImageChange[5] = false;
stateScript[5] = "onFire";
// Play the reload animation, and transition into
stateName[6] = "Reload";
stateTransitionOnTimeout[6] = "ReadyEmitterOn1";
stateTimeoutValue[6] = 0.8;
stateAllowImageChange[6] = false;
stateEjectShell[6] = false;
};Just control the ammo to turn the emitter on and off using setInventory(SwordAmmo, 1) or setInventory(SwordAmmo, 0) respectively.
I hope someone finds this useful. :)
About the author
Ben is the co-founder of Urban Brain Studios; a new independent developer of games and game development tools.
#22
07/14/2009 (12:50 pm)
Looks cool, doesn't look like it is network friendly unless you pass the commands from the server. FYI.
#23
Basically, i can't find where i'm missing a ';', and i'm starting to think it might not be the problem.
here's the error messages i get:
1>c:\Torque\TGEA_1_8_1\engine\source\T3D/shapeBase.h(557) : error C2143: syntax error : missing ';' before '*'
1>c:\Torque\TGEA_1_8_1\engine\source\T3D/shapeBase.h(557) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\Torque\TGEA_1_8_1\engine\source\T3D/shapeBase.h(557) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\Torque\TGEA_1_8_1\engine\source\T3D/shapeBase.h(602) : error C2061: syntax error : identifier 'ParticleEmitterNode'
should i post my source code for shapeBase.h? or if anyone is willing to help, i can e-mail it to them.
I'd greatly appreciate any and all help!
Thanks,
Cody Thaler
12/03/2009 (1:55 am)
I'm a student @ Dakota State Univeristy, and i'm in a game design class with Dr. Jeff Howard. I'm trying to implement this resource and i'm running into troubles when i try to rebuild the solution. I'm very much a beginner at programming, and i'm wondering anyone can help me.Basically, i can't find where i'm missing a ';', and i'm starting to think it might not be the problem.
here's the error messages i get:
1>c:\Torque\TGEA_1_8_1\engine\source\T3D/shapeBase.h(557) : error C2143: syntax error : missing ';' before '*'
1>c:\Torque\TGEA_1_8_1\engine\source\T3D/shapeBase.h(557) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\Torque\TGEA_1_8_1\engine\source\T3D/shapeBase.h(557) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\Torque\TGEA_1_8_1\engine\source\T3D/shapeBase.h(602) : error C2061: syntax error : identifier 'ParticleEmitterNode'
should i post my source code for shapeBase.h? or if anyone is willing to help, i can e-mail it to them.
I'd greatly appreciate any and all help!
Thanks,
Cody Thaler
#24
Go ahead and send along your shapeBase.h file to ben@urbanbrainstudios.com and I'll take a look.
12/03/2009 (3:08 am)
Hi Cody,Go ahead and send along your shapeBase.h file to ben@urbanbrainstudios.com and I'll take a look.
#25
12/03/2009 (3:49 pm)
i sent you a copy of the error messages, and also the shapeBase.h file. if there's anything else you might need, i'll be checking this thread often. It's CRUNCH time in my game design class. lol
#26
It looks like this is from a different resource that I don't have implemented. I think the compile error is because the "particleEmitterNode" data type is not defined. Maybe at the top, you meant to include "T3D/fx/particleEmitterNode.h" instead of or in addition to "T3D/fx/particleEmitter.h". I hope this helps and good luck with your game!
12/04/2009 (1:23 am)
I compared your shapeBase.h file with mine and the main difference is that you have at line 6:#include "T3D/fx/particleEmitter.h" class ParticleEmitter;and at line 553:
class mountedParticle
{
public:
U32 nodeNumber;
ParticleEmitterNode* particleEmitter;
};It looks like this is from a different resource that I don't have implemented. I think the compile error is because the "particleEmitterNode" data type is not defined. Maybe at the top, you meant to include "T3D/fx/particleEmitterNode.h" instead of or in addition to "T3D/fx/particleEmitter.h". I hope this helps and good luck with your game!
#27
Thanks again!
Cody Thaler
12/05/2009 (4:25 pm)
Well, i figured out that the source code i was working with was being modified by another group in my class, so basically stuff from your resource and the resource and the other group was trying to implement interfered with each other. i'm going to try putting the necessary changes with your resource again, i'll post again if there's a problem.Thanks again!
Cody Thaler
#28
-Cody
12/05/2009 (4:54 pm)
Build worked! no more problems. Thanks again for taking a look at my code!-Cody
#29
i know it's something simple, and i feel like an idiot asking this but, how do i fix this? i basically copied the torquescript example you have in this thread.
12/05/2009 (5:58 pm)
scriptsAndAssets/server/scripts/inventory.cs (134): Unable to find object: 'SwordAmmo' attempting to call function 'getName'i know it's something simple, and i feel like an idiot asking this but, how do i fix this? i basically copied the torquescript example you have in this thread.
#30
These are just from the crossbow example that comes with Torque. You'll have to use your own DTS file for the sword itself and the ammo DTS can be anything because it is never displayed.
12/05/2009 (9:06 pm)
In addition to the SwordImage Shape datablock shown in the resource, you will also need to add a Sword and SwordAmmo Item datablock. Here is an example that you can use:datablock ItemData(Sword)
{
// Mission editor category
category = "Weapon";
// Hook into Item Weapon class hierarchy. The weapon namespace
// provides common weapon handling functions in addition to hooks
// into the inventory system.
className = "Weapon";
// Basic Item properties
shapeFile = "~/data/shapes/weapons/sword/rune_blade01.dts";
mass = 1;
elasticity = 0.2;
friction = 0.6;
emap = true;
// Dynamic properties defined by the scripts
pickUpName = "a sword";
image = SwordImage;
itemType= "melee";
};
datablock ItemData(SwordAmmo)
{
// Mission editor category
category = "Ammo";
// Add the Ammo namespace as a parent. The ammo namespace provides
// common ammo related functions and hooks into the inventory system.
className = "Ammo";
// Basic Item properties
shapeFile = "~/data/shapes/particles/EnergySphere.dts";
mass = 1;
gravityMod = 0;
elasticity = 0.2;
friction = 0.6;
static = false;
// Dynamic properties defined by the scripts
pickUpName = "sword ammo";
maxInventory = 1;
image = SwordImage;
};These are just from the crossbow example that comes with Torque. You'll have to use your own DTS file for the sword itself and the ammo DTS can be anything because it is never displayed.
#31
12/06/2009 (8:08 pm)
i have the flaming sword working! i've been working with my professor to get it working, and now my question is, how would i make different states? My final goal of this resource is to have a sword that will have 4 interchangeable states. Ice, Fire, earth, and air.
#32
12/06/2009 (8:40 pm)
This is Cody Thaler by the way. i just typed this in through my professors profile by mistake
#33
In the mean time, I would just make four different sword datablocks, each with different emitter effects and switch them out depending on which effect you want. Let me know how this works out because we are thinking of doing something similar.
12/06/2009 (11:50 pm)
Unfortunately I can't think of an easy way to add multiple states because the "emitter on" state only happens in response to the sword gaining ammo. Maybe there is a way to trigger different states depending on what type of ammo is picked up?In the mean time, I would just make four different sword datablocks, each with different emitter effects and switch them out depending on which effect you want. Let me know how this works out because we are thinking of doing something similar.

Torque 3D Owner Edward