Step-by-step particle emitter-on-character tutor NOW $50 reward
by Highlander · in Torque Game Engine · 05/21/2007 (12:02 pm) · 35 replies
I'd like a *specific* step-by-step tutorial on how I can add particle emitters to the legs of my flying robot character so that when I activate jets with the controls below, particles (i.e. smoke) shoot down from them. The character was created in 3d studio max and exported. I added jet functionality to the character in the engine player.cc file and setup the following in the default.bind.cs file:
function jump(%val)
{
$mvTriggerCount2++;
}
function jjforward(%val)
{
$mvTriggerCount5++;
}
(more jet keys etc...)
I have no particular objects added to the robot in 3dmax yet, so the tutorial should cover what I need to add in 3dsmax and how it has to fit on the hierarchy. The robot in 3dmax is comprised of separate body parts, each an individual mesh (left arm, right arm, torso, head, etc) and the lower body is linked part-by-part to a biped for walking animation. The root object is Bip01.
The tutorial should also cover what needs to be added to the cs files and what steps i need to do (if any) in the particle editor. I know nothing about the particle editor other than one key to press to turn it on.
If multiple tutorials are posted, I'll go in chronological order and reward the $20 to the first one that enables me to get the jets working. Links to pre-existing tutorials are fine. You can post the tutorial as a resource afterwards. Have fun!
function jump(%val)
{
$mvTriggerCount2++;
}
function jjforward(%val)
{
$mvTriggerCount5++;
}
(more jet keys etc...)
I have no particular objects added to the robot in 3dmax yet, so the tutorial should cover what I need to add in 3dsmax and how it has to fit on the hierarchy. The robot in 3dmax is comprised of separate body parts, each an individual mesh (left arm, right arm, torso, head, etc) and the lower body is linked part-by-part to a biped for walking animation. The root object is Bip01.
The tutorial should also cover what needs to be added to the cs files and what steps i need to do (if any) in the particle editor. I know nothing about the particle editor other than one key to press to turn it on.
If multiple tutorials are posted, I'll go in chronological order and reward the $20 to the first one that enables me to get the jets working. Links to pre-existing tutorials are fine. You can post the tutorial as a resource afterwards. Have fun!
#22
Great, I got it to compile and run without crashing this time. I had misplaced the packUpdate block above the last 'if' block. I experimented some more and noticed that if you put it after the ' return retMask;' statement, at the literal end of the function, it will crash the engine, so now it rests just before that statement and it compiles fine.
I put this code:
%emitter = new ParticleEmitterNode()
{
datablock = defaultParticleEmitterNode;
emitter = myEmitterData;
};
%player.schedule(1000, mountParticleEmitter, %emitter, "mount0");
right after the section:
// Player setup...
%player.setTransform(%spawnPoint);
%player.setShapeName(%this.name);
// %player.setInventory(Crossbow,8);
// %player.setInventory(CrossbowAmmo,100);
// %player.mountImage(CrossbowImage,0);
in game.cs (I commented out the Crossbow to make room for it)
It didnt work when I tried it. I searched across all files for "defaultParticleEmitterNode" and found that there was no definition for it, so then I changed "defaultParticleEmitterNode" to "PlayerFoamParticle". No show.
I tried to increase the delay to 5000 ms but it still didn't work. It keeps reporting the error in the console:
Unable to mount particle to node: "0"
I tried changing mount0 to mount1, but it reported the same error- the number "0" didn't even change. I then tried mount2 and mount3, but with the same result:
Unable to mount particle to node: "0"
Any idea what this could be? This is a custom model with 7 nodes on it, and I think they work because the crossbow seems to mount on one and shows up in the engine.
05/24/2007 (2:00 pm)
Peter,Great, I got it to compile and run without crashing this time. I had misplaced the packUpdate block above the last 'if' block. I experimented some more and noticed that if you put it after the ' return retMask;' statement, at the literal end of the function, it will crash the engine, so now it rests just before that statement and it compiles fine.
I put this code:
%emitter = new ParticleEmitterNode()
{
datablock = defaultParticleEmitterNode;
emitter = myEmitterData;
};
%player.schedule(1000, mountParticleEmitter, %emitter, "mount0");
right after the section:
// Player setup...
%player.setTransform(%spawnPoint);
%player.setShapeName(%this.name);
// %player.setInventory(Crossbow,8);
// %player.setInventory(CrossbowAmmo,100);
// %player.mountImage(CrossbowImage,0);
in game.cs (I commented out the Crossbow to make room for it)
It didnt work when I tried it. I searched across all files for "defaultParticleEmitterNode" and found that there was no definition for it, so then I changed "defaultParticleEmitterNode" to "PlayerFoamParticle". No show.
I tried to increase the delay to 5000 ms but it still didn't work. It keeps reporting the error in the console:
Unable to mount particle to node: "0"
I tried changing mount0 to mount1, but it reported the same error- the number "0" didn't even change. I then tried mount2 and mount3, but with the same result:
Unable to mount particle to node: "0"
Any idea what this could be? This is a custom model with 7 nodes on it, and I think they work because the crossbow seems to mount on one and shows up in the engine.
#23
You will see in the code:
That error is generated when it cannot locate the emitter you passed.
05/24/2007 (2:57 pm)
Make sure the emitted you created is valid. Start off by just making a particle emitter infront of the player. Then find the ID of that emitted and mount it to the player.You will see in the code:
ConsoleMethod( ShapeBase, mountParticleEmitter, void, 4, 4, "(ParticleEmitterNode node, const char* slot)")
{
ParticleEmitterNode* particleNode;
[b]
if (!Sim::findObject(argv[2], particleNode)) {
Con::errorf("Unable to mount particle to node: \"%s\"", argv[2]);
return;
}
[/b]
object->mountParticleEmitter(particleNode, argv[3]);
}That error is generated when it cannot locate the emitter you passed.
#24
I realized that the emitters and particles are defined separately. I changed to "defaultParticleEmitterNode" to "playerFoamParticle" but I didn't change "myEmitterData" to anything. Now I tried changing them both to what seems like a matching pair from the player.cs file:
datablock ParticleData(LiftoffDust)
{
dragCoefficient = 1.0;
gravityCoefficient = -0.01;
inheritedVelFactor = 0.0;
constantAcceleration = 0.0;
lifetimeMS = 2000;
lifetimeVarianceMS = 100;
useInvAlpha = true;
spinRandomMin = -90.0;
spinRandomMax = 500.0;
colors[0] = "1.0 1.0 1.0 1.0";
sizes[0] = 1.0;
times[0] = 1.0;
};
datablock ParticleEmitterData(LiftoffDustEmitter)
{
ejectionPeriodMS = 5;
periodVarianceMS = 0;
ejectionVelocity = 2.0;
velocityVariance = 0.0;
ejectionOffset = 0.0;
thetaMin = 90;
thetaMax = 90;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvance = false;
useEmitterColors = true;
particles = "LiftoffDust";
};
I put the following in my game.cs file:
%emitter = new ParticleEmitterNode()
{
datablock = LiftoffDust;
emitter = LiftoffDustEmitter;
};
%obj.schedule(2000, mountParticleEmitter, %emitter, "mount0");
However, I get this error:
Object 'LiftoffDust' is not a member of the 'GameBaseData' data block class
starter.fps/server/scripts/game.cs (348): Register object failed for object (null) of class ParticleEmitterNode.
starter.fps/server/scripts/game.cs (349): Unable to find object: '' attempting to call function 'schedule'
I searched across all the files for GameBaseData but it doesnt exist in any of them. I was thinking perhaps I should put the datablocks from the player.cs files. I tried moving them to game.cs but same error.
Then I tried this:
%emitter = new ParticleEmitterNode()
{
datablock = LiftoffDustEmitter;
emitter = LiftoffDustEmitter;
};
%player.schedule(2000, mountParticleEmitter, %emitter, "mount0");
and got this:
starter.fps/server/scripts/game.cs (348): Register object failed for object (null) of class ParticleEmitterNode.
How can I overcome this last error??
05/24/2007 (5:09 pm)
Hi Peter,I realized that the emitters and particles are defined separately. I changed to "defaultParticleEmitterNode" to "playerFoamParticle" but I didn't change "myEmitterData" to anything. Now I tried changing them both to what seems like a matching pair from the player.cs file:
datablock ParticleData(LiftoffDust)
{
dragCoefficient = 1.0;
gravityCoefficient = -0.01;
inheritedVelFactor = 0.0;
constantAcceleration = 0.0;
lifetimeMS = 2000;
lifetimeVarianceMS = 100;
useInvAlpha = true;
spinRandomMin = -90.0;
spinRandomMax = 500.0;
colors[0] = "1.0 1.0 1.0 1.0";
sizes[0] = 1.0;
times[0] = 1.0;
};
datablock ParticleEmitterData(LiftoffDustEmitter)
{
ejectionPeriodMS = 5;
periodVarianceMS = 0;
ejectionVelocity = 2.0;
velocityVariance = 0.0;
ejectionOffset = 0.0;
thetaMin = 90;
thetaMax = 90;
phiReferenceVel = 0;
phiVariance = 360;
overrideAdvance = false;
useEmitterColors = true;
particles = "LiftoffDust";
};
I put the following in my game.cs file:
%emitter = new ParticleEmitterNode()
{
datablock = LiftoffDust;
emitter = LiftoffDustEmitter;
};
%obj.schedule(2000, mountParticleEmitter, %emitter, "mount0");
However, I get this error:
Object 'LiftoffDust' is not a member of the 'GameBaseData' data block class
starter.fps/server/scripts/game.cs (348): Register object failed for object (null) of class ParticleEmitterNode.
starter.fps/server/scripts/game.cs (349): Unable to find object: '' attempting to call function 'schedule'
I searched across all the files for GameBaseData but it doesnt exist in any of them. I was thinking perhaps I should put the datablocks from the player.cs files. I tried moving them to game.cs but same error.
Then I tried this:
%emitter = new ParticleEmitterNode()
{
datablock = LiftoffDustEmitter;
emitter = LiftoffDustEmitter;
};
%player.schedule(2000, mountParticleEmitter, %emitter, "mount0");
and got this:
starter.fps/server/scripts/game.cs (348): Register object failed for object (null) of class ParticleEmitterNode.
How can I overcome this last error??
#25
I tried your code again but still cannot get it working. Is there some simple step I may not be taking? Can I check if my model has the correct mount points etc? As far as I know I have mount points on it because the crossbow attaches to one.
05/28/2007 (3:42 pm)
Fucifer,I tried your code again but still cannot get it working. Is there some simple step I may not be taking? Can I check if my model has the correct mount points etc? As far as I know I have mount points on it because the crossbow attaches to one.
#26
05/28/2007 (3:43 pm)
Reward now $50 to the post that gets mounted particles working for me. You can see I am pretty close...
#27
The 50 bucks pulled me in here but this is something you shouldn't have to pay for.
Your problem looks like %obj is null ? and maybe the %player is null too. I don't think your passing the var's around right.
Also,Your max file should have mount0 mount1 etc etc linked to the main mesh. Check the Hierarchy and snap a screenshot of it. Look at the logs from the exporter.. search for mount0 and mount1
I think the crossbow will mount at the pivot point if theres no mount points.
Can you place a
echo("The obj is " SPC %obj ); // place this line just before you call on %obj.
%obj should match your ClientID. If nothing is returned like this.. The obj is <---- just like that means %obj has no value.
If this isn''t your problem then I would add echos in the code.. and check var's and make sure your passing a playerID as %obj.
Sorry if I was no help. ;(
If I did help.. Then I like to buy you the "Beginner Guide to Torque Programming" :) woohoo great book! and a new mouse pad. I'm not sure the book covers this exactly buuuuuuuut............. with the knowledge of this book, this should be a easy task.
GL,
Freeze
05/28/2007 (5:18 pm)
Hello,The 50 bucks pulled me in here but this is something you shouldn't have to pay for.
Your problem looks like %obj is null ? and maybe the %player is null too. I don't think your passing the var's around right.
Also,Your max file should have mount0 mount1 etc etc linked to the main mesh. Check the Hierarchy and snap a screenshot of it. Look at the logs from the exporter.. search for mount0 and mount1
I think the crossbow will mount at the pivot point if theres no mount points.
Can you place a
echo("The obj is " SPC %obj ); // place this line just before you call on %obj.
%obj should match your ClientID. If nothing is returned like this.. The obj is <---- just like that means %obj has no value.
If this isn''t your problem then I would add echos in the code.. and check var's and make sure your passing a playerID as %obj.
Sorry if I was no help. ;(
If I did help.. Then I like to buy you the "Beginner Guide to Torque Programming" :) woohoo great book! and a new mouse pad. I'm not sure the book covers this exactly buuuuuuuut............. with the knowledge of this book, this should be a easy task.
GL,
Freeze
#28
These steps is to be use with this resource.
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=8156
1. Copy dummy1 folder in the ~/data/shapes folder.
2. Copy mountedParticles.cs in ~/server/scripts.
3. open game.cs in the ~/server/scripts.
4. After the other execs add the following line:
6. Add the following lines after the crossbow or change the crossbow to the following.
7. Save and close game.cs.
8. Open Player.cs in the ~/server/scripts.
9. Search for " Allowable Inventory Items " about line 663.
10. Beneathall the other maxInv's add the following lines:
11. Save and close player.cs.
12. Open starter.fps/client/scripts/default.bind.cs.
13. Search for " crossbow " .
14. After the crossbow key binding add the following.
15. Delete config.cs and config.cs.dso in starter.fps/client. Don't worry it will
recompile when you launch Torque. Now after launch Torque and mission you can use the key to mount and dismount the particle.
16. Here the particle script I am using. This script does need some tweaking I have not had time to do it.
05/28/2007 (6:25 pm)
If you like you can send me your script I will set them up for you, also send the model i will check it. Here the steps I used. I think part problem you are put the particle code in game.cs.These steps is to be use with this resource.
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=8156
1. Copy dummy1 folder in the ~/data/shapes folder.
2. Copy mountedParticles.cs in ~/server/scripts.
3. open game.cs in the ~/server/scripts.
4. After the other execs add the following line:
exec("./mountedParticle.cs");5. Search for " // Starting equipment " line about line 314.6. Add the following lines after the crossbow or change the crossbow to the following.
// Starting equipment %player.setInventory(mounted,1); %player.setInventory(mountedAmmo,50); %player.mountImage(mountedImage,0);
7. Save and close game.cs.
8. Open Player.cs in the ~/server/scripts.
9. Search for " Allowable Inventory Items " about line 663.
10. Beneathall the other maxInv's add the following lines:
maxInv[mountedImage] = 10; maxInv[mountedImageAmmo] = 50;
11. Save and close player.cs.
12. Open starter.fps/client/scripts/default.bind.cs.
13. Search for " crossbow " .
14. After the crossbow key binding add the following.
moveMap.bindCmd(keyboard, "2", "commandToServer('use',\"mounted\");", "");15. Delete config.cs and config.cs.dso in starter.fps/client. Don't worry it will
recompile when you launch Torque. Now after launch Torque and mission you can use the key to mount and dismount the particle.
16. Here the particle script I am using. This script does need some tweaking I have not had time to do it.
function mountedImage::shootParticles(%this, %obj, %slot)
{
echo("preactivate");
%obj.setImageTrigger(1,false);
%projectile = %this.projectile;
%muzzleVector = %obj.getMuzzleVector(%slot);
%objectVelocity = %obj.getVelocity();
%muzzleVelocity = VectorAdd(
VectorScale(%muzzleVector, %projectile.muzzleVelocity),
VectorScale(%objectVelocity, %projectile.velInheritFactor));
%p = new (%this.projectileType)() {
dataBlock = %projectile;
initialVelocity = %muzzleVelocity;
initialPosition = %obj.getMuzzlePoint(%slot);
sourceObject = %obj;
sourceSlot = %slot;
client = %obj.client;
};
MissionCleanup.add(%p);
return %p;
}
datablock ParticleData(mountedParticle)
{
textureName = "~/data/shapes/particles/smoke";
dragCoeffiecient = 0.0; // 0.5
gravityCoefficient = -0.4;
inheritedVelFactor = 0.0;
// This also determines the length of the particles
lifetimeMS = 800; // 3500
lifetimeVarianceMS = 250; // 500
allowLighting = "1";
useInvAlpha = true;
spinRandomMin = -360.0;
spinRandomMax = -300.0;
colors[0] = "0.0 0.0 0.0 0.0";
colors[1] = "0.0 0.0 0.0 0.0";
colors[2] = "1.0 1.0 1.0 0.5";
colors[3] = "0.0 0.0 0.0 0.0";
sizes[0] = 0.2; // 1.0
sizes[1] = 0.5; // 2.5
sizes[2] = 1.0; // 4.0
// sizes[0] = 2.5;
// sizes[1] = 3.0;
// sizes[2] = 4.5;
// sizes[3] = 7.0;
times[0] = 0.0;
times[1] = 0.3;
times[2] = 0.6;
times[3] = 1.0;
};
datablock ParticleEmitterData(mountedEmitter)
{
ejectionPeriodMS = 10;
periodVarianceMS = 0;
ejectionVelocity = 0.0;
velocityVariance = 0.0;
thetaMin = 0.0;
thetaMax = 90.0;
particles = mountedParticle;
};
datablock ProjectileData(mountedProjectile)
{
areaImpulse = 0;
directDamage = 0;
radiusDamage = 0;
damageRadius = 5.0 ;
particleEmitter = mountedEmitter;
muzzleVelocity = 0;
velInheritFactor = 0.0;
armingDelay = 100;
isFluid = true;
lifetime = 500;
fadeDelay = 5000;
bounceElasticity = 0.0;
bounceFriction = 0;
isBallistic = false;
gravityMod = 0.20;
hasLight = true;
lightRadius = 0.1; // 6
lightColor = "0.75 0.75 0.15";
};
function mountedImage::preStep(%this, %obj, %slot)
{
%obj.unmountImage(1);
}
datablock ShapeBaseImageData(mountedImage)
{
shapeFile = "~/data/shapes/dummy1/dummy1.dts";
mountPoint = 0; // 1;
Offset = "0 0 0"; // We're not going to need this
correctMuzzleVector = false; // We're not going to need this
className = "WeaponImage";
item = dummyMount;
ammo = dummyMountAmmo; // We're not going to need this
projectile = mountedProjectile; // We're not going to need this
projectileType = Projectile;
stateName[0] = "Preactivate";
stateTimeoutValue[0] = 0.1;
stateTransitionOnTimeout[0] = "Preactivate";
stateScript[0] = "shootParticles";
stateTransitionOnTriggerDown[0] = "Activate";
stateName[1] = "Activate";
stateTransitionOnTimeout[1] = "Ready";
stateTimeoutValue[1] = 100;
stateSequence[1] = "Activate";
stateScript[1] = "preStep";
stateName[2] = "Ready";
stateTransitionOnTriggerDown[2] = "Preactivate";
// Fire the weapon. Calls the fire script which does
// the actual work.
stateName[3] = "Fire";
stateTransitionOnTimeout[3] = "Reload";
stateTimeoutValue[3] = 0.1;
stateFire[3] = true;
//stateRecoil[3] = LightRecoil;
stateAllowImageChange[3] = false;
stateSequence[3] = "Fire";
stateScript[3] = "onFire";
stateSound[3] = flamerFireSound;
// Play the relead animation, and transition into
stateName[4] = "Reload";
// stateTransitionOnNoAmmo[4] = "NoAmmo";
stateTransitionOnTimeout[4] = "Ready";
stateTimeoutValue[4] = 0.1;
stateAllowImageChange[4] = false;
stateSequence[4] = "Reload";
stateEjectShell[4] = true;
stateSound[4] = flamerReloadSound;
// No ammo in the weapon, just idle until something
// shows up. Play the dry fire sound if the trigger is
// pulled.
stateName[5] = "NoAmmo";
stateTransitionOnAmmo[5] = "Reload";
stateSequence[5] = "NoAmmo";
stateTransitionOnTriggerDown[5] = "DryFire";
// No ammo dry fire
stateName[6] = "DryFire";
stateTimeoutValue[6] = 1.0;
stateTransitionOnTimeout[6] = "NoAmmo";
stateSound[6] = flamerFireEmptySound;
};
datablock ParticleEmitterNodeData(mountedEmitterNode)
{
timeMultiple = 0.1;
};
function mountedProjectile::onCollision(%this,%obj,%col,%fade,%pos,%normal)
{
}
datablock ItemData(dummyMount)
{
category = "Weapon";
className = "Weapon";
shapeFile = "~/data/shapes/dummy1/dummy1.dts";
mass = 1;
elasticity = 0.2;
friction = 0.6;
emap = true;
pickUpName = "";
image = mountedImage;
};
datablock ItemData(dummyMountAmmo)
{
category = "Ammo";
className = "Ammo";
shapeFile = "~/data/shapes/crossbow/ammo.dts";
mass = 1;
elasticity = 0.2;
friction = 0.6;
pickUpName = "";
maxInventory = 50;
};
#29
With your excellent list I was able to get it working the first time without any trouble. Nice job. Paypal'ed.
05/31/2007 (6:38 pm)
Thanks Fucifer,With your excellent list I was able to get it working the first time without any trouble. Nice job. Paypal'ed.
#30
05/31/2007 (6:44 pm)
Your very welcome. Thanks!
#31
05/31/2007 (7:06 pm)
Actually theres one thing people should know before doing this, when you first load up the game it will give you a goofy error like you dont have a compatible version of the game. What you have to do is create a Fire directory off the particles directory and then copy the Fire.png image into it and create files fire0.png, fire1.png, etc.. up to fire7.png. This is because the default mountedparticles.cs calls for these as part of an animated texture on lines 45-53.
#32
1) get the cloud starting closer to the character (right now when he is whizzing along the clouds start far behind him)
2) activate/deactivate from script
3) right now it only works when i am moving faster than a certain speed. why?
anyone have some pointers for these? A tutorial link would be good, I cant seem to find any particle documentation on TDN but perhaps I am not looking in the right place.
05/31/2007 (7:13 pm)
Ok now I am trying to do these things:1) get the cloud starting closer to the character (right now when he is whizzing along the clouds start far behind him)
2) activate/deactivate from script
3) right now it only works when i am moving faster than a certain speed. why?
anyone have some pointers for these? A tutorial link would be good, I cant seem to find any particle documentation on TDN but perhaps I am not looking in the right place.
#33
lifetimeMS = 800;
lifetimeVarianceMS = 250;
3. I believe it is control by how many color, size and times. I will check this to be sure.
colors[0] = "0.0 0.0 0.0 0.0";
colors[1] = "0.0 0.0 0.0 0.0";
colors[2] = "1.0 1.0 1.0 0.5";
colors[3] = "0.0 0.0 0.0 0.0";
sizes[0] = 0.2;
sizes[1] = 0.5;
sizes[2] = 1.0;
sizes[3] = 2.5;
1. I will have to look at that one.
4. Not sure here what you want but I was using the 2 key to activate and deactivate. If you look above you will see the key mapping.
05/31/2007 (7:26 pm)
2. You should be able control the particle distance from the character with the following. This is what I used. lifetimeMS = 800;
lifetimeVarianceMS = 250;
3. I believe it is control by how many color, size and times. I will check this to be sure.
colors[0] = "0.0 0.0 0.0 0.0";
colors[1] = "0.0 0.0 0.0 0.0";
colors[2] = "1.0 1.0 1.0 0.5";
colors[3] = "0.0 0.0 0.0 0.0";
sizes[0] = 0.2;
sizes[1] = 0.5;
sizes[2] = 1.0;
sizes[3] = 2.5;
1. I will have to look at that one.
4. Not sure here what you want but I was using the 2 key to activate and deactivate. If you look above you will see the key mapping.
#34
05/31/2007 (7:51 pm)
Fucifer are you using the stock textures to make your smoke effect? mine show faint rectangular edges but i dont see them in your pictures above.
#35
06/01/2007 (6:28 am)
Yes I am what I have in my May 28, 2007 21:25 post is what I use for the second screen shot in my May 24, 2007 16:54 post. I did not get good result with animation textures. I change mountparticles to use the normal particles image that comes with TGE.
Torque Owner Fucifer
The next picture I change the texture and tweak the datablock.
I am going to play around with Peter resource. Peter do you have good script example on using the effect I can look at.