Game Development Community

Spuratic Rate of fire

by Steve Montgomery · in Torque Game Engine · 04/29/2006 (10:25 am) · 22 replies

I apologize for all of the posts today. I am cleaning up some problems with the game I am working on.

The issue I am posting about here is rate of fire. I adjusted the timeout values for states 3 and 4 in my weapon script (m16.cs). They are both .05 now, which should give an ROF of 600. That is a little slow for an M16, but it will work.

However, when I am in game, the ROF is no where near 600 rpm , and it is very spuratic. A few shots will fire, then a delay, then another shot, then a delay. The best forum post I found on this was from back in 2002, and it didn't really deal with this problem.

If anyone else has had this problem and fixed it, I could use the help.
Page «Previous 1 2
#1
04/29/2006 (10:50 am)
I've also seen this problem. It probably has todo with either the shapeBaseImage system, or projectile networking. Sorry if I can't be of more help ATM.
#2
04/29/2006 (11:01 am)
I think that if I really dig into it, I am going to find that the state transitions are not tied to the system clock tick directly. I figured since this was such a fundamental problem for any game with automatic weapons, someone must have already dealt with it.
#3
04/29/2006 (12:10 pm)
I'm figuring it's probably the network overhead caused by that many projectiles. Because I'm using raycasts for "projectiles" and have guns firing at that rate just fine. The projectile class as it's setup by default just _isn't_ meant to be used for realistic modern weaponry, especially when fired like that. Raycasts aren't realistic, but they're the most practical for my means.
#4
04/29/2006 (12:15 pm)
Well, I intend to move to Raycasts anyways, so now is a good time. Projectiles look silly coming out of an M-16. The good thing is it allows you to look at your ballistics and make sure you are tracking right.

Do you know of a good resource that talks about using raycasts for bullets? I haven't done a search yet myself.
#5
04/29/2006 (12:23 pm)
To overcome spuratic rate of fire I just use a looping sound for the 'fire sound', and on mouse button up play the 'aftershot' sound.
#6
04/29/2006 (12:25 pm)
I don't understand why that would work. What is causing the sporadic rate anyways? Is it the sound?
#7
04/29/2006 (1:13 pm)
As Paul said, it's probably the network overhead of producing that many fast-moving projectiles, I don't think the sound is the issue (I could be wrong). My game has the same problem. For me, raycasts are not an option. The behaviour of Torque projectiles is perfect for simulating small arms fire over long distances, which is the central concept of my game. This sporadic rate of fire has an extremely negative impact on the realism of the game, but the impact of using raycasts would be worse IMO. Either way I would also like to figure out what ultimately causes it.
#8
04/29/2006 (2:01 pm)
OK. I guess this will be my first mission for the community. I will figure this out and post what I find here or in a resource if it is appropriate to do so.

Thanks for the input everyone.
#9
04/29/2006 (2:09 pm)
The sound is definitely the issue here - I had exactly the same problem and changing to a looping fire sound works wonders.

There are a few threads about this if you have a search.

If it helps any here is my state code

// Initial start up state
   stateName[0]                     = "Preactivate";
   stateTransitionOnLoaded[0]       = "Activate";
   stateTransitionOnNoAmmo[0]       = "NoAmmo";

   // Activating the gun.  Called when the smg is first
   // mounted and there is ammo.
   stateName[1]                     = "Activate";
   stateTransitionOnTimeout[1]      = "Ready";
   stateTimeoutValue[1]             = 1.0;
   stateSequence[1]                 = "Activate";
   stateSound[1]                    = smgActivate;
   stateScript[1]                   = "onNewAmmo";

   // Ready to fire, just waiting for the trigger
   stateName[2]                     = "Ready";
   stateTransitionOnNoAmmo[2]       = "NoAmmo";
   stateTransitionOnTriggerDown[2]  = "Fire";


   // Fire the smg. Calls the fire script which does
   // the actual work.
   stateName[3]                     = "Fire";
//   stateTransitionOnTimeout[3]      = "Reload";
   stateTransitionOnTimeout[3]      = "Fire";
   stateTransitionOnTriggerUp[3]  = "SingleFireEnd";
   stateTransitionOnNoAmmo[3]       = "NoAmmo";
   stateTimeoutValue[3]             = 0.08;
   stateFire[3]                     = true;
   stateRecoil[3]                   = LightRecoil;
   stateAllowImageChange[3]         = false;
   stateSequence[3]                 = "Fire";
   stateScaleAnimation[3]           = false;
   stateScript[3]                   = "onFire";
   stateEmitter[3]                  = smgFireEmitter;
   stateEmitterTime[3]              = 0.12;
   stateSound[3]                    = smgFireloop;

   // Play the reload animation, and transition into
   stateName[4]                     = "Reload";
   stateTransitionOnNoAmmo[4]       = "NoAmmo";
   stateTransitionOnTimeout[4]      = "Ready";
//   stateTransitionOnTriggerUp[4]    = "Ready";
   stateTimeoutValue[4]             = 0.01;
   stateAllowImageChange[4]         = false;
//   stateSequence[4]                 = "Reload";
   stateEjectShell[4]               = true;
  

   // No ammo in the smg, just idle until something
   // shows up. Play the dry fire sound if the trigger is
   // pulled.
   stateName[5]                     = "NoAmmo";
   stateTransitionOnAmmo[5]         = "NewAmmo";
   stateSequence[5]                 = "NoAmmo";
   stateTransitionOnTriggerDown[5]  = "DryFire";
   stateScript[5]                   = "onNoAmmo";


   // No ammo dry fire
   stateName[6]                     = "DryFire";
   stateTimeoutValue[6]             = 0.10;
//   stateTransitionOnTimeout[6]      = "NoAmmo";
   stateTransitionOnTriggerUp[6]      = "NoAmmo";
   stateSound[6]                    = smgNoAmmo;

   stateName[7]                     = "NewAmmo";
   stateTransitionOnTimeout[7]         = "Ready";
   stateTimeoutValue[7]             = 0.1;
   stateScript[7]                   = "onNewAmmo";

   stateName[8]                     = "SingleFireEnd";
   stateSound[8]                    = smgfiresingle;
   stateTransitionOnTimeout[8]         = "Ready";
   stateTimeoutValue[8]             = 0.2;
   stateRecoil[8]                   = NoRecoil;

and a couple of extra functions referenced there that I call to change the cross hair from coloured to black depending on ammo availability

function smgImage::onnoAmmo(%this, %obj, %slot)
{
   if(%obj.client) //AI check
   {
   commandToClient(%obj.client,'SetCrossHairEmpty');
   echo("Called Crosshair Empty");
   }
}

function smgImage::onNewAmmo(%this, %obj, %slot)
{
   if(%obj.client) //AI check
   {
   commandToClient(%obj.client,'SetCrossHairLoaded');
   echo("Called Crosshair Loaded");
   }
}

and finally the audio descriptions

datablock AudioProfile(smgFireLoop)
{
   filename    = "~/data/sound/weapons/smg_loop.wav";
   description = AudioDefaultLooping3d;
   preload = true;
};

datablock AudioProfile(smgFireSingle)
{
   filename    = "~/data/sound/weapons/smg_single.wav";
   description = AudioDefault3d;
   preload = true;
};

the loop is a continuous burst sound and the single is a single shot ending that the state transitions to on trigger up.

As you can see I am using a rate of about 750 (the .08 goes straight back to fire again).


The only issue I recall having was with the recoil animation not playing correctly after this change - I added a bit of code into the shapebaseimage state system that cancelled the animation on change of state so I could use a looping recoil anim. I also added another bit of code form somewhere on the forums that allows for more than 1 recoil animation to be used by a player - you will need to search for that I am afraid.
#10
04/29/2006 (2:51 pm)
Yeah that could be an issue too, I just checked and I'd removed the sound code from mine. I'll keep that method in mind for when I go adding sound back into it.
#11
04/29/2006 (3:13 pm)
OK. So I should be able to get rid of the sound as a test and the problem should go away, right?? I will give that a try.

@David:

What is the emitter for in state[3]?? Is that for a muzzle flash?
#12
04/29/2006 (3:26 pm)
Some test results:

I have the timeout for state[3] at .1 and state[4] at .01. I pulled out all sounds and emitters.

It takes between 15 and 19 seconds to shoot 100 rounds. It still looks to me like the engine is lagging the firing process somewhere other than the state sounds.

Here is my state code for the test:

// Initial start up state
   stateName[0]                     = "Preactivate";
   stateTransitionOnLoaded[0]       = "Activate";
   stateTransitionOnNoAmmo[0]       = "NoAmmo";

   // Activating the gun.  Called when the weapon is first
   // mounted and there is ammo.
   stateName[1]                     = "Activate";
   stateTransitionOnTimeout[1]      = "Ready";
   stateTimeoutValue[1]             = 0.6;
   stateSequence[1]                 = "Activate";

   // Ready to fire, just waiting for the trigger
   stateName[2]                     = "Ready";
   stateTransitionOnNoAmmo[2]       = "NoAmmo";
   stateTransitionOnTriggerDown[2]  = "Fire";

   // 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]                    = M16FireSound;

   // Play the relead animation, and transition into
   stateName[4]                     = "Reload";
   stateTransitionOnNoAmmo[4]       = "NoAmmo";
   stateTransitionOnTimeout[4]      = "Ready";
   stateTimeoutValue[4]             = 0.01;
   stateAllowImageChange[4]         = false;
   stateSequence[4]                 = "Reload";
   stateEjectShell[4]               = true;
   stateScript[4]                   = "onReload";

And here are the onXXX functions called by the states:

//-----------------------------------------------------------------------------
// State functions for weapons
//
function M16Image::onFire(%this, %obj, %slot)
{
   %projectile = %this.projectile;

   // Steve 4-28-06
   // Decrement inventory ammo. The image's ammo state is updated
   // in weapon.cs in the ammo::oninventory function.
   %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;
}

function M16Image::onReload(%this, %obj, %slot)
{
   echo("M16 to Reload");
}

function M16Image::onNoAmmo(%this, %obj, %slot)
{
   echo("M16 to NoAmmo");
}
function M16Image::onDryFire(%this, %obj, %slot)
{
   echo("M16 to Dry Fire");
}

Anyone see anything suspicous?

- Steve
#13
04/29/2006 (3:46 pm)
Steve

I seem to remember that the extra time is being taken up transitioning between states (Im sure I tried that approach). You will notice that the transition on time out goes straight back to the fire state (I seem to remember the code in shapeimage being written to be quick if transitioning back to the same state)

I just did a test with the weapon that the script above is from and can fire 25 shots smoothly in around 2.5 seconds.

I did a further test which was to insert a blank state with a timeout of 0.001 after the fire state (FIRE -> TEST_STATE -> FIRE) and the choppy and slow fireing returned even with the looping sound. It looks as though the choppy firing is something in the statetransition code then rather than the sound afterall.

And yes the emitter in state[3] is a muzzle flash.
#14
04/29/2006 (10:30 pm)
David,

It did seem to clean up quite a bit when I used your state transitions. I put in the eighth one for the trigger up, it appeared to work. Except for one thing. If I hold down the mouse button, my gun fires non-stop whether I have ammo or not. Once I let up, the ammo check happens and I can't fire anymore if I am out. But as long as I have ammo when I start, I can hold the button down forever.

By the way, thanks a lot for your help.

I am going to dig into the state transition code in the engine and figure out what is going on. Maybe there is a way to make it work in a more deterministic fashion. I am out all of next week, so it will be a week and a half or so, but I will report back what I find here.
#15
04/30/2006 (1:36 pm)
OK. I did some work on this today. I added a console variable called 'systimems' to the FPS code in the C++ engine code. Now, if I want the system time in ms, I can type 'echo($fps::systimems)' in the console and get the actual milliseconds. Now since this is only updated at the framerate, the granularity is determined by the frame rate. On my system, I am running around 200 FPS, so that isn't a problem.

I then put some code into the 'onReload' function:

function M16Image::onReload(%this, %obj, %slot)
{
   
   echo("M16 to Reload at:" @ ($lastms - $fps::systimems)@","@$fps::systimems);
   $lastms = $fps::systimems;
}

Now, I should be able to tell how much time is between each firing event. I also set the firing timeout to .5 seconds and the reload timeout to .01 seconds.

Here is a partial dump from the console log when I hit the fire button in game:

M16 to Reload at:-26800,261133265.000000
M16 to Reload at:-768,261134031.000000
M16 to Reload at:-768,261134796.000000
M16 to Reload at:-768,261135562.000000
M16 to Reload at:0,261135562.000000
M16 to Reload at:-752,261136328.000000
M16 to Reload at:-768,261137093.000000
M16 to Reload at:-768,261137859.000000
M16 to Reload at:-768,261138625.000000
M16 to Reload at:0,261138625.000000
M16 to Reload at:-768,261139390.000000
M16 to Reload at:-768,261140156.000000
M16 to Reload at:-768,261140921.000000
M16 to Reload at:-752,261141687.000000
M16 to Reload at:-768,261142453.000000
M16 to Reload at:0,261142453.000000
M16 to Reload at:-768,261143218.000000
M16 to Reload at:-768,261143984.000000
M16 to Reload at:-768,261144750.000000

The first number is the elapsed time, the second is the actual ms. I can see a pattern here, sort of. The elapsed time is always 768, 0, or 752. I think that the 0 times are what are really creating the sporatic firing rate. There would be no perceptible difference between the other two.

So as I look into this further, I am going to figure out:

1. Why do I flip between 0 and 768mSec?
2. Why is the time not centered around the 500 mSec delay I found?

I was able to do this with a non-looping sound and with no sound and yet I got the exact same results. So I don't think it is really related to the sound in particular. There is something funky going on with the state engine in the shapebaseimage code.
#16
05/24/2006 (2:25 pm)
Found that changing the Net values in the preferences to be as below:
$pref::Net::PacketRateToClient = "30";
$pref::Net::PacketRateToServer = "32";
$pref::Net::PacketSize = "450";

Actually solves this problem with the sporadic rate of fire. Now each shot is equally spaced, sound and projectile, and each projectile spawns very close to the muzzle rather than 10-20 feet in front (at a high velocity). Networked play with a few players reports no problems lag-wise.
#17
05/24/2006 (4:51 pm)
Thanks for posting that C2, it does seem to effectively eliminate the problem.

BTW: I think sporadic is the correct spelling of the word.
#18
05/24/2006 (5:18 pm)
Ah you're right, sporadic. I'm normally an extreme spelling freak, but a quick reply and a glance at the thread title threw me off. :)
#19
05/25/2006 (4:29 pm)
Yeah, sorry about the misspelling. I am normally critical of spelling as well. I guess it was a bad day.

Anyways, thanks C2 for the information. This is very helpful. I never thought of it being in the net code.
#20
06/01/2006 (8:31 pm)
OK. I tried changing the network prefs and it appeared to have no effect. I used the console to switch them between the defaults and the ones C2 listed. Nothing.

I did figure out what my problem was with the strange timing above... it had to do with my time calculations. I fixed it and I notice that I get a pretty consistent timing between shots. But it is still to slow (200mSec) and the sounds are sporadic.

This is really a problem for me and I have no idea where to look to fix it. I guess I will just keep plugging away.
Page «Previous 1 2