Weapon Design

In which I look at how my basic approach to data-driven weapon design has taken shape over the years. Fair warning - if talking about 'variables' worries you, look away now.

Let's be honest - at some point in their career, a designer will most likely work on something that includes weapons of some description. Conflict is at the heart of gameplay and overt actual conflict is one of the easiest outs you could imagine. Then again, there's clearly a market for it.

So what I'd like to talk about today is weapon design. I'm going to limit that as well to just firearms rather than melee. Maybe I'll do a bit on melee at a later date but I'm going to see if I can actually get through a post without referencing Dark... no. Stop it.

Mowing people down with miniguns. It happens.

Syndicate


The first game I worked on that incorporated firearms was Syndicate and that has formed the backbone of how I approach weapon design. Almost all of the weapons in Syndicate were projectile weapons - pistols, shotguns, machine guns, etc. Well, I say 'projectile' - in game terms they were raycasts, but they were representing projectile weapons. The system Sean used was pretty versatile. When a weapon was fired, it would create a 'shot' - again, just a raycast - that would fly out of the front of the weapon and hit the first thing it came in contact with.

Guns were flagged as being either Semi Automatic or Fully Automatic. That is to say that the player had to press the 'trigger' each time to fire a Semi Auto or just had to hold it down to fire the Full Auto.

To make matters more interesting, a random arc was also introduced to ensure that each shot would hit a slightly different spot - otherwise you end up with a load of hit effects all in the same place which kinda sucks. This was each weapon's Accuracy* rating - whenever a shot was created, its initial direction would be rotated by a random amount constrained by this rating.

Weapons also had a maximum Range that would limit how far each shot would travel.

With these basic variables in place, it was possible to create a whole host of guns with different capabilities without requiring any special case code. The Pistol, Shotgun, Uzi Sniper Rifle and Minigun were essentially the same just with some numbers tweaked in the data. The Laser was similar but had a flag that said that the raycast for the shot wouldn't just stop at the first character it hit but continue on to it's maximum range unless it collided with a piece of scenery.

The Gauss Gun... well, that was entirely different as it was the only weapon that created an actual projectile.

You've got to admire the pluck of the infantrymen.

Battle Engine


The next time I had cause to design a weapon system, it was for Battle Engine Aquila at Lost Toys. I used the basic template we had established in Syndicate and worked from there. John "The Birch" Treece-Birch came up with a data-driven solution that enabled me to rapidly prototype new weapons and units without the need for any art or code time. This was an absolute godsend. Once the new things were deemed fun enough, the art guys could get their hands on it and start work on the final presentation without the worry that it was all going to change and they'd have to redo a lot of work. If there's one thing art guys don't like doing, it's redoing 'final' art.

Anyhow, the system was very similar but even more modular in its approach. For new readers, I'm a big fan of modular. Even the word itself. Go on, say it. Modular. It's very satisfying.

Anyway.

The Birch implemented a scripting system that all gameplay objects in the world would use. I could attach scripts to just about anything. Units would have scripts that let me tinker with things like their Movement Speed, Health and what Model they'd display. They also linked to a particular Weapon or, in some cases, more than one.

Weapons had the basic stuff from the Syndicate days - Accuracy and Range - but because they were fired by AI units rather than the player, more variables were added. (Also, in this case Range was used as an indicator for the AI to work out when they could start firing rather than dictating the actual limitation of the weapon itself for reasons I'll go into in a bit.)

First up, the Recycle rate. Nothing to do with being green, 'recycling' is a term for how quickly the Weapon can be made ready to fire again after firing. That is, it could perform a fire action every n seconds.

Then we had the Burst variable. This was how many times a weapon would fire during a fire action. Pistols or Cannons would generally fire a single shot whereas a Machine Gun or Vulcan Cannon might fire anywhere between 3 and 10 perhaps. A Burst Delay would determine the amount of time between each individual shot in the Burst - the lower the number, the faster the rounds would appear.

A Volley variable dictated how many actual Rounds would be spawned whenever the weapon was fired. This would also take the Burst into account so, for example, a weapon with a Burst of 3 and a Volley of 2 would actually fire 6 shots in total - 3 'waves' of 2 shots.

A flag was also added for Spread. This was to indicate that any shots created in a Volley would be evenly spread through the weapon's Accuracy. For something like a Shotgun where you want a chaotic spread, you'd leave this blank but for something more energy-weapon like or as part of a wave type simulation, you might want the individual projectiles fanning out evenly.

Graphically, a Muzzle Flash was a visual-only effect that was spawned whenever a Volley was fired and the Weapon would also reference the Round itself - the object that got spawned whenever it fired.

Rounds, in turn, had their own scripts and variables.

Speed would indicate how fast the Round travelled and Life would say how long it lived for. Using the pair of these variables, you could establish the actual maximum Range of the weapon. Note, thanks to the Accuracy variable, the Weapon's Effective Range - that is the maximum distance at which it's actually likely to score meaningful hits - was generally far lower this value. No sense firing at stuff that you're not really going to hit.

Some Rounds might be affected by Gravity - artillery shells or the like - so we'd have a flag for that. This also gave The Birch mathematical nightmares as he had to write code for accurately aiming a shot to take into consideration the elevation required to hit the target as well as allowing for the target's movement and the time it would take the Round to get there.

Homing missiles and things of that ilk would also require a Rotation Speed - the maximum amount they could change their course towards their target over time. To these we also added a Wiggle to enable us to perturb their course by a random amount repeatedly and give them a more chaotic look**.

Finally, each Round would have an Explosion that would be created whenever they hit something.

It's very important to note that each of these elements are entirely self-contained. They don't know what the other elements do and they don't need to. All they need to do is look after themselves. The Weapon fires the Round (or Rounds) which creates an Explosion at the end of its life. The Explosion is the only thing that does any damage to a target - there are a whole bunch of variables to play with there as well. Its this modular design that makes the system so versatile.

Now I'm not saying that this is a one-stop shop for all of your firearms needs, but it's a great starting point. You can create most weapon behaviours from these variables exposed.

Big, glowy, plasma balls.

Space Krieg


There's a similar system in place for Space Krieg but, as the game is predominantly missile-focused, more work is going into Round behaviour. There's a lot of stuff to do with target acquisition and retention that wasn't present in Battle Engine simply because all missiles in Space Krieg are fired without being locked on to anything.

There's an initial Delay where the projectile doesn't look for targets at all. After that, Rounds have an Arc and Range that describe the area in front where targets can be acquired. The target acquisition code weight targets that fall inside this area before deciding which one to lock on to. We'd also have an IFF*** flag that would instruct the missile to ignore any targets belonging to the same team (as long as that ship has a working IFF component). We also got a second variable for an Evade Arc which would nominally be equal to or greater than the Arc. If a missile had a valid target, it would only lose lock once the target was no longer in the Evade Arc, making it harder to dodge. Setting the Evade Arc to be 360 degrees would create a tenacious missile that, once it had targeted you, would never give up unless it reached the end of its lifespan. As a general rule, the Evade Arc should always be larger than the Arc otherwise you'll get all sorts of weird jittery problems around the edges.

They also have a Proximity - a distance at which the Round decides to explode anyway. This is useful for emulating Mines or warheads that spawn particularly large explosions.

That's good enough for the basic game and is very similar to how the original version worked. But we're modernising it and, since these weapons are going to be an integral part of the game's character, we need more interesting features.

Creating interesting missile weapons is very exciting indeed and there are all sorts of ways of doing it. I've always liked MIRV**** weapons, for example. Now the simple way of doing that is to link a Round up to another Round type that it spawns an amount of (Warhead Count) when it gets within (Warhead Range) of its target, but that's where you start veering away from the completely modular approach. Instead, it would be an idea to be able to attach a separate Weapon to a Round and have it run the AI for that - utilising the Volley, Burst and other code that you've already written once.

Another of my favourite games is the Front Mission series from Square Enix. They had a pretty good weapon system but my favourite missiles were the ones where the warheads were ejected straight up in the air before they fired up their engines and streaked towards their target. Something like that would want a Launch Alignment flag to determine whether or not the Round was launched facing the direction of the hardpoint or the ship itself. If the flag was set, it would spend it's Delay time orienting itself with the direction the ship was pointing at launch.

This will allow us to make cool, anime-style missiles that fire out of the back of the ship before arcing around to fly forwards.

You could also layer on some kind of Tumble variable that would start the projectile tumbling over itself when launched for a prescribed amount of time before behaving normally. Again, another nod to Front Mission and the 'Donkey' missile launcher that used to casually 'flip' warheads out before they'd ignite and streak off towards their target. Very cool. Maybe we'd even use a long Tumble for Mines or the like - make them a bit more dynamic?

Anything after that is detail work - trying to give each weapon it's own flavour. Mostly, that'll be down to the visual effects you use but the behaviours count for quite a bit too.

Other things to consider would be to introduce Charge times - the amount of delay between a fire command being issued and the first Burst being fired - think R-Type's main weapon. One caveat here is how that feeds back into the UI design. If you'd want the player to be unable to do anything else during the charge up time, that has to be properly reflected in their interface. Then you get into a potentially thorny subject of inputs from one phase overlapping into the next, which isn't really something we want to get into...

Or being able to propagate override data down from the Weapon - for example making the last piece of ammo in a clip do extra damage for that everso satisfying, "I only just killed him with my last chance" feeling. As much as I like this as a mechanic, my feeling is that it only really applies when there's a direct and immediate correlation between the shot you've just fired and the impact. With this game, most hits or kills happen off screen or some time after the shot was fired, so you'd lose that connection.

All of these things that I've talked about just deal with direct damage - ie: when something hits something else it lowers the target's health. The next stage is to talk about interesting Status Effects - other things that happen on impact - but each of these generally requires custom code. Sure, there's a way you could open up attribute modifiers to be all nice and modular, but that's really going into architecture now and I've rambled for long enough this time.

Still, I do love a good DOT*****

* The final Accuracy rating would also take the character's Perception value into account.
** Those missile launchers at the battle of Geonosis were the main inspiration there. Hella inaccurate but looked pretty cool arcing overhead.
*** Identity Friend Foe. How aircraft tell if other aircraft are friendly or not.
**** Multiple Independent Rocket Vehicle. A missile that spawns other missiles at some point during its flight.
***** Damage Over Time. Target continues to take damage after the initial impact has passed. Think poison or burning or something.

Comments

Popular Posts