State machine question
by Steve D · in Torque Game Engine · 02/08/2007 (5:55 pm) · 17 replies
Hi all, I get how the state machine works but ironically I can't get it work. Here is a sample state machine I coded. I realize it may not be fully done but at this point all I want to do is animate the gun. I'm using a weapon model from the weapon pack.
statename[0] = "Preactivate";
stateTransitionTimeout[0] = "idle";
StateSequence[0] = "Preactivate";
statename[1] = "Idle";
statesequence[1] = "idle";
stateTransitionOnTriggerDown[1] = "fire";
statename[2] = "fire";
StateTransitionOnTimeout[2] = "reload";
statefire[2] = "true";
statesequence[2] = "shoot";
statetimeoutvalue[2] = "10";
statename[3] = "reload";
statesequence[3] = "reload";
The thing is when I hit the fire button nothing happens. Right now I'm not that concerned with seeing a reload animation or anything else, I just want something to happen to make sure I'm doing it correctly. Also in the weapons folder there is a script file that looks like this -
datablock TSShapeConstructor(w_vulcandts)
{
baseShape = "./w_vulcan.dts";
sequence0 = "./vulcan_activate.dsq Activate";
sequence1 = "./vulcan_deactivate.dsq deactivate";
sequence2 = "./vulcan_idle.dsq idle";
sequence3 = "./vulcan_reload.dsq reload";
sequence4 = "./vulcan_run.dsq run";
sequence6 = "./vulcan_shoot.dsq shoot";
};
Am I supposed to add this script to anything to make the game engine recognize it?
statename[0] = "Preactivate";
stateTransitionTimeout[0] = "idle";
StateSequence[0] = "Preactivate";
statename[1] = "Idle";
statesequence[1] = "idle";
stateTransitionOnTriggerDown[1] = "fire";
statename[2] = "fire";
StateTransitionOnTimeout[2] = "reload";
statefire[2] = "true";
statesequence[2] = "shoot";
statetimeoutvalue[2] = "10";
statename[3] = "reload";
statesequence[3] = "reload";
The thing is when I hit the fire button nothing happens. Right now I'm not that concerned with seeing a reload animation or anything else, I just want something to happen to make sure I'm doing it correctly. Also in the weapons folder there is a script file that looks like this -
datablock TSShapeConstructor(w_vulcandts)
{
baseShape = "./w_vulcan.dts";
sequence0 = "./vulcan_activate.dsq Activate";
sequence1 = "./vulcan_deactivate.dsq deactivate";
sequence2 = "./vulcan_idle.dsq idle";
sequence3 = "./vulcan_reload.dsq reload";
sequence4 = "./vulcan_run.dsq run";
sequence6 = "./vulcan_shoot.dsq shoot";
};
Am I supposed to add this script to anything to make the game engine recognize it?
#2
02/08/2007 (7:50 pm)
I'll give it a shot. What is really confusing to me is the starter.fps doesn't have the tsshapeconstructor for the crossbow, just player animations.
#3
Common practice for weapon models is to create the animations in a single file, on a single time line thus no TSShapeconstructor is needed. This is how the crossbow is set up and why it doesn't need a TSShapeconstructor.
The exis weapon pack uses separate dsq files for animations (which is why you need the TSShapeconstructor) and I don't know why.
02/08/2007 (8:00 pm)
That's what I said in the last part of my post above. Common practice for weapon models is to create the animations in a single file, on a single time line thus no TSShapeconstructor is needed. This is how the crossbow is set up and why it doesn't need a TSShapeconstructor.
The exis weapon pack uses separate dsq files for animations (which is why you need the TSShapeconstructor) and I don't know why.
#4
You'll need to have a function in the fire state to do the actual work (deincrement ammo, create the projectile etc).
E.g.
That would jump to a function named accordingly:
E.g.
Substitue CrossbowImage for whatever your ShapeBaseImageData datablock is called.
02/08/2007 (8:07 pm)
One more thing RE firing of the weapon:You'll need to have a function in the fire state to do the actual work (deincrement ammo, create the projectile etc).
E.g.
stateScript[3] = "onFire";
That would jump to a function named accordingly:
E.g.
function CrossbowImage::onFire(%this, %obj, %slot)
{
%projectile = %this.projectile;
// Decrement inventory ammo. The image's ammo state is update
// automatically by the ammo inventory hooks.
%obj.decInventory(%this.ammo,1);
// Determin initial projectile velocity based on the
// gun's muzzle point and the object's current velocity
%muzzleVector = %obj.getMuzzleVector(%slot);
%objectVelocity = %obj.getVelocity();
%muzzleVelocity = VectorAdd(
VectorScale(%muzzleVector, %projectile.muzzleVelocity),
VectorScale(%objectVelocity, %projectile.velInheritFactor));
// Create the projectile object
%p = new (%this.projectileType)() {
dataBlock = %projectile;
initialVelocity = %muzzleVelocity;
initialPosition = %obj.getMuzzlePoint(%slot);
sourceObject = %obj;
sourceSlot = %slot;
client = %obj.client;
};
MissionCleanup.add(%p);
return %p;
}Substitue CrossbowImage for whatever your ShapeBaseImageData datablock is called.
#5
02/08/2007 (8:24 pm)
Ah ok I understand about the dts file. Then one more question, how do you know what different states there and what they are called from a single dts file?
#6
One last thing, I just noticed you're trying to set up a minigun. There's a special way this has to be done, it's a different procedure than other weapons.
Let me know if you need a hand.
02/08/2007 (8:28 pm)
Showtool will give you this information. Though, if you have access to the source file you could retrieve the animation names from there. You create nodes and use those to specify the different animations / sequence names. You can also set up a player in this fashion if you really wanted, i.e. one file that contains all the animations.One last thing, I just noticed you're trying to set up a minigun. There's a special way this has to be done, it's a different procedure than other weapons.
Let me know if you need a hand.
#7
What's interesting now is when I load that file up and I pick up the mini gun it doesn't mount the image anymore, it only does it when I'm loading the above cs file.
02/08/2007 (8:30 pm)
Figures, I just picked the minigun out of the pack at random :)What's interesting now is when I load that file up and I pick up the mini gun it doesn't mount the image anymore, it only does it when I'm loading the above cs file.
#8
02/08/2007 (8:56 pm)
Here's a script that will get the exis exchange vulcan behaving like a minigun://--------------------------------------------------------------------------
// Vulcan image which does all the work. Images do not normally exist in
// the world, they can only be mounted on ShapeBase objects.
// Load the TSShapeConstructor first in order for animations to work
exec("~/data/shapes/w_vulcan/w_vulcan.cs")
datablock ShapeBaseImageData(w_vulcanImage)
{
// Basic Item properties
shapeFile = "~/data/shapes/w_vulcan/w_vulcan.dts";
emap = true;
// Specify mount point & offset for 3rd person, and eye offset
// for first person rendering.
mountPoint = 0;
eyeOffset = "0.2 0.5 -0.2";
// When firing from a point offset from the eye, muzzle correction
// will adjust the muzzle vector to point to the eye LOS point.
correctMuzzleVector = true;
// Add the WeaponImage namespace as a parent, WeaponImage namespace
// provides some hooks into the inventory system.
className = "WeaponImage";
// Projectile && Ammo.
item = vulcan;
ammo = vulcanAmmo;
mag = vulcanMag;
projectile = vulcanProjectile;
projectileType = Projectile;
casing = VulcanShell;
shellExitDir = "1.0 0.3 1.0";
shellExitOffset = "0.15 -0.56 -0.1";
shellExitVariance = 15.0;
shellVelocity = 3.0;
// Images have a state system which controls how the animations
// are run, which sounds are played, script callbacks, etc. This
// state system is downloaded to the client so that clients can
// predict state changes and animate accordingly. The following
// system supports basic ready->fire->reload transitions as
// well as a no-ammo->dryfire idle state.
//--------------------------------------
stateName[0] = "Preactivate";
stateTransitionOnLoaded[0] = "Activate";
stateTransitionOnNoAmmo[0] = "NoAmmo";
//--------------------------------------
stateName[1] = "Activate";
stateSequence[1] = "Activate";
stateSound[1] = WeaponUseSound;
stateTimeoutValue[1] = 0.7;
stateTransitionOnTimeout[1] = "Ready";
//--------------------------------------
stateName[2] = "Ready";
stateSpinThread[2] = Stop;
stateTransitionOnTriggerDown[2] = "Spinup";
stateTransitionOnNoAmmo[2] = "NoAmmo";
//--------------------------------------
stateName[3] = "NoAmmo";
stateSpinThread[3] = Stop;
stateTransitionOnAmmo[3] = "Reload";
stateSequence[3] = "NoAmmo";
stateTransitionOnTriggerDown[3] = "DryFire";
//--------------------------------------
stateName[4] = "Spinup";
stateSpinThread[4] = SpinUp;
stateSound[4] = VulcanSpinupSound;
stateTimeoutValue[4] = 0.5;
stateWaitForTimeout[4] = false;
stateTransitionOnTimeout[4] = "Fire";
stateTransitionOnTriggerUp[4] = "Spindown";
//--------------------------------------
stateName[5] = "Fire";
stateSequence[5] = "Fire";
stateSequenceRandomFlash[5] = true;
stateSpinThread[5] = FullSpeed;
stateSound[5] = VulcanFireSound;
stateRecoil[5] = LightRecoil;
stateAllowImageChange[5] = false;
stateScript[5] = "onFire";
stateFire[5] = true;
stateEjectShell[5] = true;
stateTimeoutValue[5] = 0.1;
stateTransitionOnTimeout[5] = "Fire";
stateTransitionOnTriggerUp[5] = "Spindown";
stateTransitionOnNoAmmo[5] = "EmptySpindown";
//--------------------------------------
stateName[6] = "Spindown";
stateSound[6] = VulcanSpinDownSound;
stateSpinThread[6] = SpinDown;
stateTimeoutValue[6] = 1.0;
stateWaitForTimeout[6] = true;
stateTransitionOnTimeout[6] = "Ready";
stateTransitionOnTriggerDown[6] = "Spinup";
//--------------------------------------
stateName[7] = "EmptySpindown";
stateSound[7] = VulcanSpinDownSound;
stateSpinThread[7] = SpinDown;
stateTimeoutValue[7] = 0.5;
stateTransitionOnTimeout[7] = "NoAmmo";
//--------------------------------------
// Play the reload animation, and transition into
stateName[8] = "Reload";
stateTransitionOnNoAmmo[8] = "NoAmmo";
stateTransitionOnTimeout[8] = "Ready";
stateTimeoutValue[8] = 2.0;
stateAllowImageChange[8] = false;
stateSequence[8] = "Reload";
stateEjectShell[8] = false;
//--------------------------------------
stateName[9] = "DryFire";
stateSound[9] = VulcanDryFireSound;
stateTimeoutValue[9] = 0.5;
stateTransitionOnTimeout[9] = "NoAmmo";
};
//-----------------------------------------------------------------------------
#9
Make sure all those sequences (dsq's) exist in the folder where the dts is.
02/08/2007 (9:00 pm)
Almost forgot, alter your TSShapeConstructor to look like this (change is in bold):datablock TSShapeConstructor(w_vulcandts)
{
baseShape = "./w_vulcan.dts";
sequence0 = "./vulcan_activate.dsq Activate";
sequence1 = "./vulcan_deactivate.dsq deactivate";
sequence2 = "./vulcan_idle.dsq idle";
sequence3 = "./vulcan_reload.dsq reload";
sequence4 = "./vulcan_run.dsq run";
[b]sequence5 = "./vulcan_spin.dsq spin";[/b]
sequence6 = "./vulcan_shoot.dsq shoot";
};Make sure all those sequences (dsq's) exist in the folder where the dts is.
#10
02/08/2007 (9:11 pm)
Interesting, thank you. The gun still doesn't do anything when I press fire, I realize I don't have an onfire function coded for the projectile but shouldn't it at least spin up?
#11
In the meantime here's some quick tips:
- Check the console for errors / warnings
- Make sure the TSShapeConstructor script is being executed (and that it's being executed before the ShapeBaseImageData datablock where the states are defined)
- Make sure that the sequence names specified in the TSShapeConstructor script match the names of the dsq files
- Make sure all dsq's are present and in the same folder as the dts
Goodluck!
02/08/2007 (9:23 pm)
Unfortunately I have to go offline now, life calls. I'll check back tomorrow to see how you're doing and yes the fire animation should still play without an onFire method. In the meantime here's some quick tips:
- Check the console for errors / warnings
- Make sure the TSShapeConstructor script is being executed (and that it's being executed before the ShapeBaseImageData datablock where the states are defined)
- Make sure that the sequence names specified in the TSShapeConstructor script match the names of the dsq files
- Make sure all dsq's are present and in the same folder as the dts
Goodluck!
#12
02/09/2007 (1:08 pm)
Sigh I have looked at everything, double checked, but can't find anything wrong, no errors or anything. Is there anyway to see if the state machine is even being executed at all?
#13
to
Also, you need to make your reload state go back to Idle or Preload, otherwise you won't be able to fire again!
--Amr
02/09/2007 (4:49 pm)
Hi Steve, I just had a look at your datablock at the top of the page and I noticed that you need to change the linestateTransitionTimeout[0] = "idle";
to
stateTransition[b]On[/b]Timeout[0] = "idle";
Also, you need to make your reload state go back to Idle or Preload, otherwise you won't be able to fire again!
--Amr
#14
You could also do it in the onMount method:
02/09/2007 (5:07 pm)
Also, make sure your weapon is loaded (has ammo) or it won't fire. I think there's a cmd you can use along the lines of:setImageStateLoaded = true;
You could also do it in the onMount method:
%obj.mountImage(vulcanImage, 0, true);
#15
I have one more question
item = vulcan;
ammo = vulcanAmmo;
mag = vulcanMag;
projectile = vulcanProjectile;
projectileType = Projectile;
I'm not sure what these values are doing?
02/09/2007 (8:48 pm)
Thanks guys, it turns out I didn't have the ammo set, once I set it I was good to go. At least I learned a lot by over troubleshooting a very simple problem :)I have one more question
item = vulcan;
ammo = vulcanAmmo;
mag = vulcanMag;
projectile = vulcanProjectile;
projectileType = Projectile;
I'm not sure what these values are doing?
#16
Ammo = the datablock for the ammo item. This datablock will define things like maxInventory of said ammo and will also hook into the ammo class to handle things like incrementing, de-incrementing of ammo, what to do when ammo is collected by a player etc.
Mag = my own custom code. Similar to ammo, allows for weapons to use a magazine. Safe to delete this value.
Projectile = the projectile datablock. Takes care of the actual projectile that's fired from the gun, explosions and decals when projectile impacts, how much damage to apply to objects etc.
projectileType = well, the projectile type. Typically this will always = projectile. Basically, it's used as a reference in the onFire function where the projectile is created:
02/10/2007 (8:05 pm)
Item = the weapon's item datablock. This is what's used to place the weapon in a mission. The onPickup method mounts the item's image to the player.Ammo = the datablock for the ammo item. This datablock will define things like maxInventory of said ammo and will also hook into the ammo class to handle things like incrementing, de-incrementing of ammo, what to do when ammo is collected by a player etc.
Mag = my own custom code. Similar to ammo, allows for weapons to use a magazine. Safe to delete this value.
Projectile = the projectile datablock. Takes care of the actual projectile that's fired from the gun, explosions and decals when projectile impacts, how much damage to apply to objects etc.
projectileType = well, the projectile type. Typically this will always = projectile. Basically, it's used as a reference in the onFire function where the projectile is created:
// Create the projectile object %p = new (%this.projectileType)()
#17
02/11/2007 (7:10 am)
Thanks Tim, you've been a great help, appreciate it.
Torque Owner Tim Heldna
datablock TSShapeConstructor(w_vulcandts) { baseShape = "./w_vulcan.dts"; sequence0 = "./vulcan_activate.dsq Activate"; sequence1 = "./vulcan_deactivate.dsq deactivate"; sequence2 = "./vulcan_idle.dsq idle"; sequence3 = "./vulcan_reload.dsq reload"; sequence4 = "./vulcan_run.dsq run"; sequence6 = "./vulcan_shoot.dsq shoot"; };Leave this script in the same folder as the weapon and make sure it is being executed:
E.g.
exec("~/data/shapes/w_vulcan/w_vulcan.cs");I would execute it from the weapon script file (the one with the state machine).
The script is responsible for the animations of the weapon, without it animations won't work.
I don't know why they set animations up this way for a weapon, common practice is to create the animations within a single file (for weapons).