Game Development Community

Semi-auto fire rate

by Richard Preziosi · in Torque Game Engine · 09/22/2009 (6:42 pm) · 19 replies

How could I set up my weapon to shoot only once, currently if you hold the mouse button it keeps firing after the weapon is reloaded. Tried every resource I could find by searching and none would work in 1.5.2.

Thanks in advance.

#1
09/22/2009 (7:24 pm)
Through the state-machine in your weaponImage.

Post your state system for your weapon and I'll tell you what to change. Or, if you want to solve it yourself the key is not to use 'stateTransitionOnTimeout' (which causes an automatic transition) instead you want to use 'stateTransitionOnTriggerUp' in order to get the transition to a post-fire or reload state.
#2
09/22/2009 (7:57 pm)
Here is some code for a semi-auto from Crimeforce.

stateName[0]                     = "Preactivate";
   stateTransitionOnLoaded[0]       = "Activate";
   stateTransitionOnNoAmmo[0]       = "NoAmmo";

   stateName[1]                     = "Activate";
   stateTransitionOnTimeout[1]      = "Ready";
   stateTimeoutValue[1]             = 0.7;
   stateSequence[1]                 = "Activated";

   stateName[2]                     = "Ready";
   stateTransitionOnNoAmmo[2]       = "NoAmmo";
//   stateTransitionOnNoAmmo[2]       = "WaitForReload";
   stateTransitionOnTriggerDown[2]  = "Fire";
   stateSequence[2]                 = "Ready";
   stateScript[2]                   = "onReady";
   stateTransitionOnReload[2]       = "Reload";

   stateName[3]                     = "Fire";
//   stateTransitionOnTimeout[3]      = "Ready";
   stateTransitionOnTimeout[3]      = "ReloadAnim";
   stateTimeoutValue[3]             = 0.10;
   stateFire[3]                     = true;
   stateRecoil[3]                   = LightRecoil;
   stateAllowImageChange[3]         = false;
   stateSequence[3]                 = "Fire";
   stateScript[3]                   = "onFire";
   stateSound[3]                    = M700FireSound;
   stateEmitter[3]                  = BulletFireSmoke;
   stateEmitterTime[3]              = 1.0;
   stateEmitterNode[3]              = "muzzlePoint";
//   stateTransitionOnNoAmmo[3]       = "NoAmmo";
   stateEjectShell[3]               = true;

   stateName[4]                     = "Reload";
   stateTransitionOnNoAmmo[4]       = "NoAmmo";
   stateTransitionOnTimeout[4]      = "FinishedReloading";
   stateTimeoutValue[4]             = 3.0; // 0.25 load, 0.25 spinup
   stateAllowImageChange[4]         = false;
   stateSequence[4]                 = "Reload";
   stateScript[4]                   = "onReload";
   stateSound[4]                    = Ak47ReloadSound;

   stateName[5]                     = "FinishedReloading";
   stateTransitionOnTimeout[5]      = "Ready";
   stateTimeoutValue[5]             = 0.01;
   stateScript[5]                   = "onFinishedReloading";

   stateName[6]                     = "NoAmmo";
   stateTransitionOnAmmo[6]         = "Reload";
   stateSequence[6]                 = "NoAmmo";
   stateAllowImageChange[6]         = false;
   stateScript[6]                   = "onNoAmmo";
   stateTransitionOnTriggerDown[6]  = "DryFire";

   stateName[7]                     = "DryFire";
   stateSound[7]                    = WeaponDryFireSound;
   stateScript[7]                   = "onDryFire";
   stateTimeoutValue[7]             = 0.13;
   stateTransitionOnTimeout[7]      = "NoAmmo";

   stateName[8]                     = "ReloadAnim";
//   stateSound[8]                    = WeaponDryFireSound;
//   stateScript[8]                   = "onReloadAnim";
   stateTimeoutValue[8]             = 1.05;
   stateTransitionOnTimeout[8]      = "Ready";
#3
09/22/2009 (8:08 pm)
Quote:
How could I set up my weapon to shoot only once, currently if you hold the mouse button it keeps firing after the weapon is reloaded
Willbkool's example will still exhibit that behavior. In order to make it work like you're asking for you'll have to change state#3 to read like this:
stateName[3] = "Fire"; 
// stateTransitionOnTimeout[3] = "Ready"; 
//stateTransitionOnTimeout[3] = "ReloadAnim"; // remove this line
//stateTimeoutValue[3] = 0.10;                // remove this line
stateTransitionOnTriggerUp[3] = "ReloadAnim"; // add this line
stateFire[3] = true; 
stateRecoil[3] = LightRecoil; 
stateAllowImageChange[3] = false; 
stateSequence[3] = "Fire"; 
stateScript[3] = "onFire"; 
stateSound[3] = M700FireSound; 
stateEmitter[3] = BulletFireSmoke; 
stateEmitterTime[3] = 1.0; 
stateEmitterNode[3] = "muzzlePoint"; 
// stateTransitionOnNoAmmo[3] = "NoAmmo"; 
stateEjectShell[3] = true;
#4
09/22/2009 (8:20 pm)
I just checked in-game, it doesn't fire if the mouse button is kept pressed. So the code should work, although they put everything into one weapon file. I added the same code to my game for a M1 Garand and it works perfectly.
#5
09/22/2009 (9:14 pm)
I checked and tested before I posted and it does exhibit that behavior -- the weapon transitioned from fire to reload and back to fire again so long as the button was held -- perhaps you have something extra tucked away in the onReload() callback in state# 4...
#6
09/23/2009 (1:56 am)
// Fire the weapon. Calls the fire script which does 
   // the actual work.
   stateName[3]                     = "Fire";
   //stateTransitionOnTimeout[3]      = "Reload"; //Automatic
   //stateTimeoutValue[3]             = 0.2; //Automatic
   stateTransitionOnTriggerUp[3]    = "Reload"
   stateFire[3]                     = true;
   stateRecoil[3]                   = LightRecoil;
   stateAllowImageChange[3]         = false;
   stateSequence[3]                 = "Fire";
   stateScript[3]                   = "onFire";
   stateSound[3]                    = CrossbowFireSound;

This code makes my gun not show up and not fire at all. And i'm using the starter.fps crossbow.

This is what my console puts out
>>> Advanced script error report.  Line 893.
>>> Some error context, with ## on sides of error halt:
   stateName[3]                     = "Fire";

   //stateTransitionOnTimeout[3]      = "Reload"; //Automatic

   //stateTimeoutValue[3]             = 0.2; //Automatic

   stateTransitionOnTriggerUp[3]^   = "Reload"

   stateFire[3]                     = true;

## ##  stateRecoil[3]                   = LightRecoil;

   stateAllowImageChange[3]         = false;

   stateSequence[3]                 = "Fire";

   stateScript[3]                   = "onFire";

   stateSound[3]                    = CrossbowFireSound;
#7
09/23/2009 (2:04 am)
There's a missing semi-colon at the end of your stateTransitionOnTriggerUp line.

stateTransitionOnTriggerUp[3] = "Reload";
#8
09/23/2009 (2:07 am)
Quote:There's a missing semi-colon at the end of your stateTransitionOnTriggerUp line.

Get's people everytime, myself included every once in a while. :)
#9
09/23/2009 (2:12 am)
Thanks a ton, gonna put a post-it on my comp saying make sure to put ; so i don't forget again.

Thanks all.

Just posting another change incase someone stumbles upon this, to make the gun fire as fast as you can press the mouse button with the above fix also change the reload part to:
// Play the relead animation, and transition into
   stateName[4]                     = "Reload";
   stateTransitionOnNoAmmo[4]       = "NoAmmo";
   //stateTransitionOnTimeout[4]      = "Ready"; //Check for a reload time for each bullet
   //stateTimeoutValue[4]             = 0.8;  //actual reload time for each bullet
   stateTransitiononTriggerUp[4]    ="Ready"; //No bullet reload time
   stateAllowImageChange[4]         = false;
   stateSequence[4]                 = "Reload";
   stateEjectShell[4]               = true;
   stateSound[4]                    = CrossbowReloadSound;
#10
10/11/2009 (12:52 am)
I've Come to a new problem, the code works beautifully, however the sound cuts out as soon as you let go of the mouse button. If I hold the mouse button the sound finishes though. Is this fixable, I've tried moving the statesound around, but it doesn't do anything to fix it.

Thanks
#11
10/11/2009 (2:46 am)
Try a "stateTimeoutValue" long enough so your sound can play, but short enough for the semi-auto to seem effective.

You may also need to highly modify the sound itself to play right with your scripts, I consider myself pretty skilled at Sound Editing but it still took some time to work around the scripts.

For example... make sure there is NO wasted time before or after the actual sound plays in the file and you may even need to modify further depending on the sounds being used in your specific application, but thats a whole differant story beyond that.

Hope that helped! :)
#12
10/11/2009 (5:37 am)
Yea the stateTimeoutValue definitely helps, just sucks cause even my 409 millisecond single shot sound wont' fully play without it set to .2, which makes every other click fire, instead of every click. Gonna have to dig into the c++ and find where it stops sounds and look at editing it. Thanks again, let you know how it goes.

Edit: Yeah, .2 really isn't even long enough to play a 409 millisecond clip completely.

I thought perhaps if i add the sound to the onfire function it may play all the way through, since the onTriggerUp is setting it to "reload". However nothing I have tried will play the sound. Seems pretty limiting as it is now.
#13
10/11/2009 (11:08 am)
i fixed my sound cut out problem by commenting out the stateSound and jus adding in

alxplay(soundfile, position);

in the weapons onFire meathod
#14
10/11/2009 (4:04 pm)
@Rich: Ya I think most of my SingleShots I managed to get down to 250ms and I notice a small bit of clipping even then (which in my case actually sounds about right for what it should be).

Edit: Oh ya and I use a Timeout of .1 (forgot to add that before)
#15
10/11/2009 (5:59 pm)
Yeah that's what I've been wanting to do Scooby, can't seem to get it to work though. I've tried pointing to the datablock GlockFireSound and even the file itself, can't seem to get it to work at all. Where exactly are you putting the alxPlay in the onfire function?
#16
10/11/2009 (10:07 pm)


here is my onFire

function CatalystImage::onFire(%this, %obj, %slot)
{
   parent::onFire(%this, %obj, %slot);
   %projectile = %this.projectile;
   %spread = %this.projectileSpread;
   %ammoInClip = %obj.getWeaponAmmoClip();

   // Check if there is enough ammo in the clip
   if( %ammoInClip > 0 )
   {
      // Remove bullet from clip
      %ammoInClip = %ammoInClip - 1;

      // Show the new Ammo in Clip Amount on screen
	%obj.setWeaponAmmoClip( %ammoInClip );
    %obj.client.setClipAmountHud(%ammoInClip);

      // Adjust Ammo Amount on screen
      %ammoOnPile = %obj.getInventory(%this.projectileAmmo.getName(),"amount");
      %obj.client.setAmmoAmountHud(%ammoOnPile, %this.projectileAmmo);

      // Check if that was the last bullet in the clip
      if( %ammoInClip == 0 )
      {
         // No more ammo, make sure the state switches to Reload!
         %obj.setImageAmmo( %slot, false );
      }
   }
   else
   {
      // No ammo in clip
      %obj.setImageAmmo(%slot,false);

      // Abort onFire, because there is no Ammo in the clip
      return 0;
   }

   %this.projectileAmmo.onInventory(%obj,%obj.getInventory(%this.projectileAmmo.getName(),"amount"));

   // Get the muzzle vector.  This is the dead straight aiming point of the gun
   %vector = %obj.getMuzzleVector(%slot);

	// Get our players velocity.  We must ensure that the players velocity is added
			//   onto the projectile
			%objectVelocity = %obj.getVelocity();

			// Determine scaled projectile vector.  This is still in a straight line as
			//   per the default example
			%vector1 = VectorScale(%vector, %projectile.muzzleVelocity);
			%vector2 = VectorScale(%objectVelocity, %projectile.velInheritFactor);
			%velocity = VectorAdd(%vector1,%vector2);

			// Determine our random x, y and z points in our spread circle and create
			//   a spread matrix.
			%x = (getRandom() - 0.5) * 2 * 3.1415926 * %spread;
			%y = (getRandom() - 0.5) * 2 * 3.1415926 * %spread;
			%z = (getRandom() - 0.5) * 2 * 3.1415926 * %spread;
			%mat = MatrixCreateFromEuler(%x @ " " @ %y @ " " @ %z);

			// Alter our projectile vector with our spread matrix
			%velocity = MatrixMulVector(%mat, %velocity);

   // Create the projectile object
   %p = new (%this.projectileType)() 
			{
				dataBlock        = %projectile;
				initialVelocity  = %velocity;
				initialPosition  = %obj.getMuzzlePoint(%slot);
				sourceObject     = %obj;
				sourceSlot       = %slot;
				client           = %obj.client;
				isArmorPiercing  = %projectile.isArmorPiercing;
                wrappedDecalsMode = %projectile.wrappedDecalsMode;
                        //target = %obj.getLockedTarget(%slot);
			};
         
   // Do some recoil if this weapon has the required field:  recoilType
   //if (%this.recoilType !$= "")
      //CommandToClient(%obj.client, 'DoRecoil', %this.recoilType);
      
   %pos = %obj.getPosition();

   if( %ammoInClip <= 10 )
   {
      if(%this.lowAmmoSoundsCount > 0)
	   {
	      %snd = %this.stateSoundOnFireLowAmmo[getRandom(%this.lowAmmoSoundsCount - 1)];
         alxPlay(%snd, getWord(%pos, 0), getWord(%pos, 1), getWord(%pos, 2));
	   }  
   }
   else
   {
      if(%this.fireSoundsCount > 0)
	   {
	      %snd = %this.stateSoundOnFire[getRandom(%this.fireSoundsCount - 1)];
         alxPlay(%snd, getWord(%pos, 0), getWord(%pos, 1), getWord(%pos, 2));
	   }  
   }
   
   MissionCleanup.add(%p);
   return %p;
}
#17
10/12/2009 (4:12 am)
Never come across anything like that Scooby. Are your sounds still set up in the begining like:
datablock AudioProfile(SoundOnFire)
{
filename = "~/data/sound/fire.wav";
description = AudioClose3d;
preload = true;
};

I'm understanding what you have going on, different sounds for when ammo gets low, or at least that's what it looks like to me.

Should I not be able to play the sound by just using:
function clientCmdPlayFireSound()
{
	$fireSound = alxPlay(SoundOnFire);
}

then use this command to play it in the onFire function?
commandToClient(%cl, 'PlayFireSound');

Really not grasping this, would think it would be as easy as using alxplay(SoundOnFire); but that doesn't seem to be the case.
#18
10/12/2009 (4:47 am)
A friend and I were able to fix it in TGEA, by editing the source and commenting out an SFX_DELETE we found which clears the audio at the end of the fire state. Working on porting our game over to TGEA anyways so this is great.

Thanks a lot guys.
#19
10/12/2009 (6:12 pm)
Glad you got it fixed in tgea. Yes my audio is defined the same way as normal with the audioProfiles @ the top..not sure why it wouldnt work for you though..but hey you got tgea fixed lol