Game Development Community

dev|Pro Game Development Curriculum

Cone of Fire with Recoil

by Bryce "Cogburn" Weiner · 08/11/2004 (4:23 pm) · 35 comments

Download Code File

EXPLANATION
-----------
This is my first resource so please expect that there might be a few errors that need to be addressed. I am a programmer but I am still on the C++ learning curve. My code could probably be done better.

Excuses out of the way, this resource adds two new functions to the TGE: a cone of fire and recoil effect. Both of these effects are implemented in several major-market FPS games, most notably the Medal of Honor and Battlefield series. This was inspired by this resource.

The first function is a "cone of fire" effect. Projectiles fired from the weapon do not always follow the crosshairs, rather fall within a theoretical cone extending from the muzzle of the weapon. As the weapon fires, the cone expands. Between rounds the crosshairs retract, shrinking the cone. This resource includes a crosshair GUI object that contains scripting hooks for setting the cone of fire per weapon datablock, as well as a hook for communicating client-side cone size to the server WITHOUT using a mask bit in the engine.

The second effect is an alteration of the pitch of the player based on the current cone of fire.

Both effects combined make for an extremely realistic weapons behavior. This resource has not been tested on vehicle mounted weapons, but there is no reason that I can see why it would not work.

You can see a sample in this movie. Note that our GUI is hardly finished. ;)

INSTRUCTIONS
------------
Unzip the file above into your engine/game/fps/ directory and add it to your project. Recompile.

Open Starter.fps/server/scripts/weapons.cs and add the following:
function serverCmdUpdateClientCoF(%client,%bloom)
{
	//	Save it on the client object for later use.
	%client.currentCoF = %bloom;
}

In the same file, change WeaponImage::onMount to look like the following:
function WeaponImage::onMount(%this,%obj,%slot)
{
   // Images assume a false ammo state on load.  We need to
   // set the state according to the current inventory.
   if (%obj.getInventory(%this.ammo))
      %obj.setImageAmmo(%slot,true);
      
  commandToClient(%obj.client,'CoFUpdate',%this.baseCoF,%this.coFBloom);   
	%obj.currentCoF = %this.baseCoF;
}

Open Starter.fps/client/scripts/game.cs and add the following:
function clientCmdCoFUpdate(%baseCoF, %coFBloom)
{
   CoFCrosshair.addBloom = %coFBloom;
   CoFCrosshair.baseBloom = %baseCoF;
   pitch(0 - (%coFBloom / 2)); // Season to taste
   CoFCrosshair.setBloom(0);
}

function updateServerCoF(%bloom)
// This function is called from the crosshair GUI object from within the engine.
{
	commandToServer('updateClientCoF',%bloom);
	echo ("Sending Bloom:" @ %bloom);
}

Open Starter.fps/client/ui/playGui.cs and replace the current Crosshair datablock with this one.
new GuiCoFCrossHairHud(CoFCrosshair) {
      profile = "GuiDefaultProfile";
      horizSizing = "center";
      vertSizing = "center";
      position = "384 256";
      extent = "256 256";
      minExtent = "8 2";
      visible = "1";
      damageFillColor = "0.000000 1.000000 0.000000 1.000000";
      damageFrameColor = "1.000000 0.600000 0.000000 1.000000";
      damageRect = "50 4";
      damageOffset = "0 32";
      baseBloom = "5";
      addBloom = "10";
      maxBloom = "64";
      crossHairColor = "0.800000 0.800000 0.800000 1.000000";
   };

Open the file for the weapon you wish to add this effect to. In the ShapeBaseImageData datablock definition, add the following:
baseCoF = 5;  // Season to taste
   coFBloom = 10;  // Season to taste
   projectileCount = 1;  // Provides for multiple projectile weapons like shotguns

In the same file, change the onFire method of your weapon to match the following:
function SMGImage::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);

	%spread = %obj.client.currentCoF / 2000;  // Season to taste

	// Create each projectile and send it on its way 
	for(%shell=0; %shell<%this.projectileCount; %shell++)
	{
		// 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;
	   };
	   MissionCleanup.add(%p);
	}
   commandToClient(%obj.client,'CoFUpdate',%this.baseCoF,%this.coFBloom);
   return %p;
}

Load your game and pull the trigger.

Once again, this is my first resource so please post if there are problems with your implementation. I am not by any means guarenteeing that this will work on all systems, and of course you should have read this resource fully and backed up your files prior to attempting to add this to your project. And .... I could have always forgotten something.

If anyone is looking to improve on this, I'd really like to see the addition of a bitmap array rather than drawing the cursor with dglDrawLine. You could then allow for custom crosshairs per weapon. This is just beyond my C++ ability at the moment.

Thanks to Harold "LabRat" Brown for the mask bit alternative.
Page «Previous 1 2
#1
08/11/2004 (2:49 pm)
If you cut and paste, replace all of the ´ with '
#2
08/11/2004 (6:59 pm)
You have to re-upload the .zip, that one is bugged :(
#3
08/11/2004 (7:01 pm)
If the above link is bad, you can find it here.
#4
08/11/2004 (7:23 pm)
Thanks alot, this works great!
#5
08/12/2004 (3:13 pm)
Skimming through this shows one really large problem if you care at all about cheating ...

The client tells the server what it's CoF is. This means someone could hack their client to set the CoF to be whatever they want, thus improving their accuracy. All of the CoF stuff should be handled on the server, and the server tell the client what it should look like.

If you're making a single player game, then it doesnt really matter either way, but for a multiplayer game you really dont want this.

Remember: Server should always be authorative. Any time you allow the client to tell the server what it's doing without having the server validate it, you're in big trouble for multiplayer.

Hope that helps,

Tom.
#6
08/13/2004 (12:53 pm)
I've thought of that, but without using engine code there isn't a way of making it secure as well as cheap on processing. What you suggest for a multiplayer game, if all done in scripting, would be a large tax on the server for such a small effect in the scope of the game.

The nature of our project does not allow for client-side modifications. We got rid of the uncompiled main.cs as well as added a proprietary encryption scheme to replace zip file support. We've got the client locked down for all but packet sniffing and spoofing, but since you can never stop that 100% anyway we figured that in the end it was a tradeoff.

I mentioned it a few times, but you COULD modify this resource further and make it a shapeBase object so it ghosts automatically on the server. A mask bit would be all that is then required for updates. Since most TGE projects already overload the existing mask bits, this was another reason to abandon this method. Maybe my next resource should be a patch to increase the mask bits to 64. ;)

There is another problem inherent in this example. The CoF reduction is based on client-side FPS. The CoF reduction is faster or slower based on the client's FPS at any given moment. This could (and should) be improved so that it works off of processor ticks for the reduction computations, rather than just piggy-backing in the onRender function. I plan on making this change and updating the resource in the next few days.
#7
08/14/2004 (8:28 am)
This maybe a bit offtopic but could you please write a resource to show how to get rid of the uncompiled main.cs, I think it is a large security risk and have for some time, its nice to know that someone managed to get passed this problem
#9
08/15/2004 (2:26 am)
Thanks
#10
08/15/2004 (3:37 pm)
I see no reason why all of this can't be in C++.
#11
08/15/2004 (6:57 pm)
You're totally right, Josh. I could see that going in. I'm currently rewriting this resource in C++ and will release it seperately since the functionality will be totally different. I've already added new variables such as shrinkTime and shrinkAmount so the retraction of the crosshair can be unique per weapon.

In my project I have maxed out the available mask bits forcing me to piggy-back on something I've already assigned. As a result, anything I write I have to modify for a HEAD version. No biggie, just added time until I can post it as a resource.

Are you aware of a way to communicate the required information without the use of mask bits?
#12
08/16/2004 (1:29 pm)
and i totally disagree. you'll definetly have cheating with it implemented like this. just because they can't 'decompile' your .cs, or see your .cs doesn't mean anything. trust nothing from the client. you're going to have people shooting laser rifles. they can modify the outgoing network packet, dynamically patch the memory of the game AFTER loading to cause it to ignore calls to update it's CoF so it never sends back a smaller CoF to the server. there are atleast a dozen ways to do it, and it will be done.

'unseen source' does not mean 'can not be cheated.'
#14
09/07/2004 (11:19 am)
I am in the process of converting this into C++ but I am having a small problem, how in C++ would I call the "pitch" command from a gui?
#15
12/23/2004 (5:43 pm)
edit: well i fixed the no fire issue, but theres still no recoil and the reticule doesnt move at all
#16
03/04/2005 (6:07 pm)
I'll search for another recoil tutorial. I searched this so I could use it on a auto snipe in my game and I want to save some time.
#17
03/14/2005 (3:41 pm)
The original zip file link seems to be broken and the author's e-mail address seems to also be incorrect. Is there anyone with a copy of the zip above who could send it to me so that I can learn from this very substantial resource?

Thank you,
-Greg
#18
03/15/2005 (10:09 pm)
This resource is, in a word, awesome.

However, I have two problems:

1. The cone of fire works well as told, however, it seems that my 'bloom' is being
set back to the base bloom after every shot, how can I make the bloom take
longer to revert back to the base bloom?

2. the crosshair is too heavy for my game and I'd like to change the arrows into single-pixel-wide lines. I assume the dglDrawLine portions of code are the ones I'm looking for but which ones are drawing the crosshair arrows?

Anyway this really added some much-needed substance to my game. Thank you for your time and effort in bringing this to us.

--EDIT-- Just noticed that post about the reduction being based on framerate,
if you manage to make that change involving processor ticks or (preferably) a
way to set a %bloomReductionTime variable with millisecond values... please let me know, thanks =-)
#19
04/18/2005 (1:54 am)
I have the same request as Gregory Dudding, can someone please email the zip file to me cos all the links for it on this page seem to be corrupt.

Thanks
#20
04/18/2005 (7:25 am)
I'm also trying to dl the file but no luck. All the links seem broken.
May someone email the zip to me please ?

Thanks in advance.
Page «Previous 1 2