Game Development Community

Advanced weapon behvaiour

by Daniel Buckmaster · in Torque Game Engine · 03/25/2008 (3:03 am) · 4 replies

I'm not that experienced with the ShapeBaseImage state system. What I want to know is how complicated certain effects would be to put into a state system.

-The Plasma Cannon
This was a cool idea thought up by one of the modelers I work with. To charge the weapon, you hold down the right mouse button. It gradually builds up heat (partile effects get bigger and bigger...). If you let go of the trigger, the heat decreases until you hit the button again. To fire, you hit the left mouse button. When you fire, the hat the weapon has built up is used to create the projectile. So if you're only got a tiny amount of heat, you get a wussy little plasma bolt. If you're right in the sweet spot, you get a huge shot. However, if you're too hot, then the gun explodes due to overload.

-The Bolter
This is a little simpler. The bolter fires four-round bursts whenever you pull the trigger.

-Halo's Plasma Rifle
I guess you know what thi means. It's an automatic weapon, but each time you fire, heat builds up. If the gun gets too hot, it overheats and you can't use it for a few seconds while it vents steam.

I'm sure there are a few other complicated examples, but basically - can these three feasibly be done with the state system?

About the author

Studying mechatronic engineering and computer science at the University of Sydney. Game development is probably my most time-consuming hobby!


#1
03/25/2008 (4:22 am)
I believe The Bolter and the Plasma Rifle will be easy to do, but the plasma Cannon I dont think will be possible without changing a few things in the engine.

The Bolter:
In the OnFire event of the Weapon you can just create 4 projectiles similar to this:
function AssaultCannonImage::onFire(%this, %obj, %slot)
{
	%projectile = %this.projectile;
	
	// set the number of projectiles we are going to fire
	%shellcount = 1;
	
	// Decrement inventory ammo. The image's ammo state is update
	// automatically by the ammo inventory hooks.
	%obj.decInventory(%this.ammo, %shellcount);
	
	// 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));

	%spread = 6/1000; // This defines the spread of the projectiles. If no value is set the gun will fire deadly accurate.	
	%spread = %spread $= "" ? 0.001 : %spread;
	%spread = %spread <= 0 ? 0.001 : %spread;
	
	// 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
	%muzzleVelocity = MatrixMulVector(%mat, %muzzleVelocity);
	
	// Returns axis angle attitude specification
   %shipAxisAngle = getWords(%obj.getTransform(),3,6); 
   
	// Create the projectile object
	%o = new (%this.projectileType)() {
		dataBlock        = %projectile;
		initialVelocity  = %muzzleVelocity;
		initialPosition  = %obj.getMuzzlePoint(%slot);
      initialRotation  = %shipAxisAngle;
		sourceObject     = %obj;
		sourceSlot       = %slot;
		client           = %obj.client;
	};
	MissionCleanup.add(%o);

// 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
	%muzzleVelocity = MatrixMulVector(%mat, %muzzleVelocity);

	// Create the projectile object
	%p = new (%this.projectileType)() {
		dataBlock        = %projectile;
		initialVelocity  = %muzzleVelocity;
		initialPosition  = %obj.getMuzzlePoint(%slot);
      initialRotation  = %shipAxisAngle;
		sourceObject     = %obj;
		sourceSlot       = %slot;
		client           = %obj.client;
	};
	MissionCleanup.add(%p);

// 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
	%muzzleVelocity = MatrixMulVector(%mat, %muzzleVelocity);

	// Create the projectile object
	%q = new (%this.projectileType)() {
		dataBlock        = %projectile;
		initialVelocity  = %muzzleVelocity;
		initialPosition  = %obj.getMuzzlePoint(%slot);
      initialRotation  = %shipAxisAngle;
		sourceObject     = %obj;
		sourceSlot       = %slot;
		client           = %obj.client;
	};
	MissionCleanup.add(%q);

// 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
	%muzzleVelocity = MatrixMulVector(%mat, %muzzleVelocity);

	// Create the projectile object
	%r = new (%this.projectileType)() {
		dataBlock        = %projectile;
		initialVelocity  = %muzzleVelocity;
		initialPosition  = %obj.getMuzzlePoint(%slot);
      initialRotation  = %shipAxisAngle;
		sourceObject     = %obj;
		sourceSlot       = %slot;
		client           = %obj.client;
	};
	MissionCleanup.add(%r);

	return %r;
}
Note - above code might need some fixing, but its a start.

Check out this Charging resource, it can very easily be modified to timeout when the to 'hot': www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=2971
#2
03/25/2008 (5:03 am)
For the bolter, I meant the weapon would actually fire (run through the whole state sequence) four times for each trigger press. Like the Battle rifle in Halo 2.

There's a point to this thread, believe me (sorry for being all wierd), but I'm gonna wait for more replies...
#3
03/26/2008 (9:12 am)
An idea - what about some sort of wait state/ short timer between projectile onFire event?

Basically call onFire 4x from your firing script for each trigger.
#4
03/26/2008 (9:24 am)
Here's my datablock for a 3-round burst weapon. My version of Torque is pretty tweaked, so not everything in this datablock will work for you, but the states should work fine.

datablock ShapeBaseImageData(Type95Image)
{
   shapeFile = "~/data/shapes/guns/type95.dts";
   emap = true;

   zoomx = 4;
   zoombmp = "sniper2";
   mountPoint = 0;
   eyeOffset = "0.3 0.1 -0.3";//left-right,forward-back,up-down
   correctMuzzleVector = true;//true;//false
   className = "WeaponImage";

    mass = 12;
   
   // Projectile && Ammo.
   item = Type95;
   ammo = Type95Ammo;
   clip = Type95Clip;
   projectile = Type95Projectile;
   projectileType = Projectile;
   
   fireKick = 2.5;
   KickRecoverTime = 1;
   
   reloadTime = 4;
   
   lightType = WeaponFireLight;
   lightRadius = 10;
   lightTime = 50;
   lightColor = "0.5 0.5 0.25";

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

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

   stateName[2]                     = "Ready";
   stateTransitionOnNoAmmo[2]       = "NoAmmo";
   stateTransitionOnTriggerDown[2]  = "Fire";

   stateName[3]                     = "Fire";
   stateTransitionOnTimeout[3]      = "Fire2";
   stateTimeoutValue[3]             = 0.1;
   stateEmitterTime[3]				= 0.1;
   stateEmitter[3]					= GunSmokeEmitter;
   stateFire[3]                     = true;
   stateRecoil[3]                   = LightRecoil;
   stateAllowImageChange[3]         = false;
   stateSequence[3]                 = "Fire";
   stateScript[3]                   = "onFire";
   stateSound[3]                    = Type95FireSound;

   stateName[4]                     = "Reload";
   stateTransitionOnNoAmmo[4]       = "NoAmmo";
   stateTransitionOnTimeout[4]      = "Ready";
   stateTimeoutValue[4]             = 0.092;
   stateAllowImageChange[4]         = false;
   stateEjectShell[4]               = true;

   stateName[5]                     = "NoAmmo";
   stateTransitionOnAmmo[5]         = "Reload";
   stateSequence[5]                 = "NoAmmo";
   stateTransitionOnTriggerDown[5]  = "DryFire";

   stateName[6]                     = "DryFire";
   stateTimeoutValue[6]             = 0.3;
   stateScript[6]                   = "onFire";
   stateTransitionOnTimeout[6]      = "NoAmmo";
   
   stateName[7]						= "ReClip";
   stateSequence[7]                 = "Reload";
   
   stateName[8]                     = "Fire2";
   stateTransitionOnTimeout[8]      = "Fire3";
   stateTimeoutValue[8]             = 0.1;
   stateEmitterTime[8]				= 0.1;
   stateEmitter[8]					= GunSmokeEmitter;
   stateFire[8]                     = false;
   stateRecoil[8]                   = LightRecoil;
   stateAllowImageChange[8]         = false;
   stateSequence[8]                 = "Fire";
   stateScript[8]                   = "onFire";
   stateSound[8]                    = Type95FireSound;
   
   stateName[9]                     = "Fire3";
   stateTransitionOnTimeout[9]      = "WaitForRelease";
   stateTimeoutValue[9]             = 0.1;
   stateEmitterTime[9]				= 0.1;
   stateEmitter[9]					= GunSmokeEmitter;
   stateFire[9]                     = false;
   stateRecoil[9]                   = LightRecoil;
   stateAllowImageChange[9]         = false;
   stateSequence[9]                 = "Fire";
   stateScript[9]                   = "onFire";
   stateSound[9]                    = Type95FireSound;
   
   stateName[10]="WaitForRelease";
   stateTransitionOnTriggerUp[10]="Reload";
   
};