Weapon System in Top-Down Shooter

Started by
10 comments, last by Sean_Seanston 13 years ago
I'm coding a top-down shooter for a college project soon so I have some questions about logical ways of implementing a weapon system.

The player might be able to use (or the code should allow straightforward implementation of) many kinds of weapons such as:
- Melee weapons
- Pistols
- Machine guns
- Shotguns
- Grenades
- Special weapons that might perhaps freeze or poison enemies

Basically, I want some logical and flexible way of coding the weapons of the game without limiting myself to firing simple projectiles that cause X amount of damage going at Y speed firing Z often.

Some of those are similar enough, a pistol and machine gun would likely be different mostly in damage and rate of fire but then you move to something like a shotgun where you need several projectiles fired at once in some kind of cone pattern and grenades where maybe they could have the ability to go over walls and eventually must stop and explode. C4 could be another, where pressing fire causes one to be placed on the ground and maybe detonated remotely. Again, maybe a molotov cocktail would be a grenade that creates a fire effect on detonation and detonates on impact.

So a lot of weapons would have very different behaviour and it wouldn't simply be a matter of altering a few values like number of projectiles, damage, rate of fire etc.

Being a relative newbie, I'm looking for some advice on this. How would YOU do it? Are there a few methods in particular that would tend to come to mind to experienced programmers for such a situation? Does anyone know of any open source games with similar situations coded in C++?

My current ideas for options are as follows:
1. Complete Hard Coding
Sloppy, hard to change, might involve tons of long ifs and switches but it would get the job done. Last resort but simplest design-wise with very little thinking involved. Just make a class for every weapon type and if player is holding that gun, run through its specific behaviour in some fire() function. No complication about how to deal with a grenade passing over objects versus a stream of bullets but it won't impress design-wise.

2. XML and some kind of hard-coded set of behaviours
So I'd store variables like DAMAGE, RATE_OF_FIRE and AMMO_PER_MAG etc. in an XML file and also have some kind of variable like WEAPON_TYPE. That would be chosen from a list looking something like GUN, SHOTGUN, THROWABLE, PLANTABLE, MELEE etc. where the value would correspond to some hard coded functions in C++ that dealt with the behaviour of melee weapons as distinct from throwable grenades and the like. This way seems alright, but then it almost seems too in between to me. Sure, the XML is keeping variables nice and organized in easy to change files but the actual behaviour of the weapons are locked away in .cpp files so recompilation is still required for big important changes. Is that a bad idea?
Of course, once you have the logic of what any shotgun should act like all sorted out, you probably won't need to change it much and the XML variables will help with balancing and also hopefully allow you to create new kinds of shotgun (pump action vs semi auto for instance) with XML only.
As for something more complicated like a gun that poisons enemies... perhaps a function could be called when collision with an enemy is detected that would implement such special abilities like freezing or poisoning and weapons could also have a SPECIAL_EFFECT variable? These effects would then, like weapon behaviour, need to be hard coded and associated with labels for XML to reference them. So such behaviour is still locked away in C++.

I imagine that significant parts will have to be hard coded no matter what unless I start learning a scripting language or some such and implement behaviours that way, but the idea of that right now seems quite daunting and is it really worth it? I suppose what I'm really worrying about, since I pretty much know that either system will work, is if my ideas will make design sense. Is a significant amount of XML justified if the weapons can't even have their most significant attribute altered by it? I'm probably overthinking and trying too hard to achieve a flexible design that's really above me right now, but I can't help wondering.
Advertisement
Sounds like you have a schedule, however far away the due date is. You may want to consider coding in what you currently know if learning a new interface would take a significant amount of time.

You can use C++ with weapons base classes that expose virtual functions to be used by the collision, physics and rendering engines. Then create higher classes of weapons for types that share more characteristics (projectiles, spells, etc.), perhaps again with virtual functions as you'll want specific behavior for weapons that inherit from those classes.

You can also use something like Python, which is a bit quicker for development and still may give you the performance you need.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

If you see yourself needing to do a lot of extending, or prove a lot of extensibility, then you'll probably want to go with option 2.

I started doing something like in the Unity engine, and this is basically how I had it sorted out:


  • Character owns a weapon.
  • Weapon spawns one or more, projectiles of type X, any way it wants, and in any position relative to the weapon (out in front, or 3-4 projectiles in front organised in a semi-circle, projectile that shoots straight up, etc)
  • Projectile X updates itself and controls it's own movement depending on the type (normal bullet travelling forwards, homing missle, thrown grenade, etc)


So, in this way, you have a single generic weapon code object that simply reads and acts on data from the XML, like so:
<weapon type="pistol">	<projectile type="bullet" relative_start_position="0 0 1"></weapon><weapon type="shotgun">	<projectile type="bullet" relative_start_position="-1 0 1">	<projectile type="bullet" relative_start_position="0 0 1">	<projectile type="bullet" relative_start_position="1 0 1"></weapon><weapon type="missle_launcher">	<projectile type="homing_missle" relative_start_position="0 0 1"></weapon>


This way, the 1 weapon code class just reads in the data and spawns the correct projectile types in relation to the weapon whenever the character fires.

The projectile types will probably have to be at least partially coded so you just have the ProjectileBullet, ProjectileHomingMissle and other classes update the projectile with physics, or without, to go straight forward, or constantly update to head towards another character, or really whatever you need them to do. You could also quite easily make a timed grenade that will fall down onto the ground and then explode after 3 seconds.

Hopefully all you will have to code specifically is the bullet specific classes, but you should probably add XML data for them as well so you could really easily create new projectile types without heaps of extra work, as long as it uses one of the basic projectile types.

<projectile type="bullet">	<color>0xffffffff</color>	<update_logic>bullet</update_logic></projectile><projectile type="super_bullet">	<color>0xffff0000</color>	<update_logic>bullet</update_logic></projectile><projectile type="shotgun_pellet">	<color>0xff7f007f</color>	<update_logic>bullet</update_logic></projectile><projectile type="homing_missle">	<color>0xff7f007f</color>	<update_logic>homing_missle</update_logic></projectile><projectile type="missle">	<color>0xff7f007f</color>	<update_logic>bullet</update_logic>	<speed>10</speed></projectile>


As you see, now when you update, you just look for the type of the projectile and update it based on that instead of having to create a single code class for each individual projectile type. You just need one for each projectile that actually updates in a different way instead of just being named something different.

So, the "bullet", "super_bullet", "missle" and "shotgun_pellet" all update in the same way, because all they do is travel immediately forwards from their spawn position. So, it's really simple to just create a new weapon and projectile type that is already based on that.

You'd also want to add things like damage, max projectile lifetime (assuming it doesn't hit anyone in the first 2-3 seconds).
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Quote:Original post by Endar
So, in this way, you have a single generic weapon code object that simply reads and acts on data from the XML, like so:
*** Source Snippet Removed ***

This way, the 1 weapon code class just reads in the data and spawns the correct projectile types in relation to the weapon whenever the character fires.


Yes... that seems a good idea. I'd kind of forgotten about the design of the Projectile class. Sounds good as far as I can see right now. You could put weapon firing rate and damage etc. in the XML weapon tag too.

Quote:Original post by EndarThe projectile types will probably have to be at least partially coded so you just have the ProjectileBullet, ProjectileHomingMissle and other classes update the projectile with physics, or without, to go straight forward, or constantly update to head towards another character, or really whatever you need them to do. You could also quite easily make a timed grenade that will fall down onto the ground and then explode after 3 seconds.


Yeah, sounds good. Should be easy enough to make it work.

One thing though: What about melee weapons?
I suppose one way would be to fire forward an invisible projectile with some kind of ridiculous speed but a very short range. That'd keep it within the same style as other weapons.
Would there be a more logical way though? Obviously it should be at its simplest something like checking if an enemy is within a certain range of the front of the player and then inflicting damage but would that fit into this system easily?

Quote:Original post by EndarAs you see, now when you update, you just look for the type of the projectile and update it based on that instead of having to create a single code class for each individual projectile type. You just need one for each projectile that actually updates in a different way instead of just being named something different.


Yeah, seems a good idea.

That was a lot of help, thanks.
Quote:Original post by Sean_Seanston
One thing though: What about melee weapons?
I suppose one way would be to fire forward an invisible projectile with some kind of ridiculous speed but a very short range. That'd keep it within the same style as other weapons.

It depends if you need to get it working quickly, or if you have time to implement something a little different as well.

Ideally, you'd want projectiles and melee weapons to be different, and on melee weapons (assuming this is a 3d game), you'd have another xml file, etc, etc, and create physics/collision spheres that are attached to bones on the weapon that the player is holding. Then, when the melee animation is played, you simply check for collision between the collision spheres on the player's weapon and the enemy.

But if you don't have time for that, the way you suggested is a pretty good way to fake it. But, you might want to add some sort of firing delay in, because you'll want to be playing an animation of the player swinging the weapon, so you won't want the projectile to fire until a specific point in the animation. That's also something that you'd want to place in the xml data.
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Well it's a 2D game, forgot to mention that.

Would it then be best just to have 2 different types of weapon: melee and non-melee? Or would that be sort of a kludge? I want to avoid as much hard coding as possible.

How might something like planting remote C4 be done? You'd want to select C4, press a button to place it and then press the same or a different button to detonate any placed C4. Here we get into alternate fire... and the weapon having some kind of control and tracking mechanism over its projectiles.

I suppose we'd have to have each weapon keep track of its projectiles for a start. Then we'd want primary fire to launch each weapon's projectiles but secondary fire has to depend on its projectile type in the case of C4. So we could have secondary fire delegate to the projectile class to call some kind of function in the projectile BUT... ideally it would be nice to have a more flexible system where something like a projectile-less secondary function could be implemented onto a weapon like... an energy wave blowing outward or even giving the carrier temporary invulnerability.

So I'm thinking that really... weapon alternate abilities should probably not depend directly on the weapon's projectiles. In which case... it seems to me that maybe hard coding weapon alternate abilities (like REMOTE_DETONATION, INVULNERABLE, SPEED_BOOST, MELEE) and then assigning them through XML in a similar way to your projectile type idea would be a reasonable way to go.

Thoughts?
Hard-coding some behavior and 'attaching' it to objects sounds like a fair approach, but if you need a lot of flexibility, you may want to use a scripting language instead. Plain data only gets you so far - if you come up with a totally distinct weapon later on, chances are you'll need to add some code for it anyway.

The main benefit of data/scripting is that it's faster to tune things - no long recompile required. It's especially powerful if you can tweak things while running the game. It's one of the reasons why I like high-level languages so much: I can test different things almost instantly - there's no compile stage standing in the way.


Either way, the C4 'weapon' could place C4 projectiles in the world, and with secondary fire, trigger them to explode. Similar to grenades, which would explode after a certain time, and rockets, that explode on impact, it's simply a different way to determine when to apply damage.
Create-ivity - a game development blog Mouseover for more information.
I would only like to point out, melee and projectile based weapons are not necessary distinct. You may for example attach a bayonet to a rifle and you then have a projectile based weapon with a secondary melee attack. So, the best solution is probably to have several hard-coded basic weapon behavior and you then simply attach them to your weapon.
To make it a little more flexible you can build behaviors in terms of events. The projectile weapon may for example have a shot event (probably triggered with the primary or alternate fire button) and a reload event. Your C4 explosive may have detonate event which may be triggered using a timer or alternate fire and so on.
Let suppose you want to create a rifle with bayonet, so you attach to the weapon a projectile weapon behavior and a melee weapon behavior. You then choose to trigger the shot event of the projectile weapon using the primary fire and melee weapon attack using the alternate fire. You have then to add a projectile type and decide how projectiles are fired from the weapon. If you later decide to also include a grenade launcher in it, you simply have to add a different projectile weapon behavior with different properties and with the events triggered in a different way.
Quote:Original post by Captain P
Hard-coding some behavior and 'attaching' it to objects sounds like a fair approach, but if you need a lot of flexibility, you may want to use a scripting language instead. Plain data only gets you so far - if you come up with a totally distinct weapon later on, chances are you'll need to add some code for it anyway.


Scripting sounds like a great idea at least in theory, the only thing holding me back is the time/difficulty involved in learning.

I had a glance at Python the other day... it's something I'd like to learn eventually given the amount of talk I often hear about it and ease of use etc.

Do you think it'd be practical to learn how to script something like this with Python given my timeframe? The game itself needs to be finished something around... May/June I think so really there's a lot of time in theory depending on what else gets in the way.
Would it take much time to get to the level of scripting something like this?
I don't want to go down one route and find myself wasting tons of time or making things outright impossible for me, but then learning a new scripting language would certainly look good and maybe it'd even speed up development in places and offset the time taken to learn.

Quote:Original post by apatriarca
To make it a little more flexible you can build behaviors in terms of events. The projectile weapon may for example have a shot event (probably triggered with the primary or alternate fire button) and a reload event. Your C4 explosive may have detonate event which may be triggered using a timer or alternate fire and so on.
Let suppose you want to create a rifle with bayonet, so you attach to the weapon a projectile weapon behavior and a melee weapon behavior.


Hmmm... sounds good.

So I'd be hard-coding a set of these weapon events and cobbling them together, along with projectile types if appropriate, to create weapons. That seems to probably be the best solution so far... it seems to account for melee and projectile weapons pretty well as well as allowing more unusual effects through hard-coded projectiles.

I think I'll go with something like that if I can't see any problems with it in the future.
Quote:Original post by Sean_Seanston
Do you think it'd be practical to learn how to script something like this with Python given my timeframe? The game itself needs to be finished something around... May/June I think so really there's a lot of time in theory depending on what else gets in the way.

I'd say that's doable. The first time I ever touched Python was during a 3-month game-development class. Here's a blog post about that project. Half a year is not enough to become really proficient with a language, but Python is fairly easy to learn, so you should definitely be able to write something like this in a couple of months. I've been using it ever since to speed up various tasks, so I'm definitely happy I gave it a go.

I can't say much about integrating a script interpreter into another program, as I've never done that. Instead, I always program straight in Python. But from what I've heard, Lua is easier to integrate, so that may be worth investigating.
Create-ivity - a game development blog Mouseover for more information.

This topic is closed to new replies.

Advertisement