It always starts simple
For my platformer game All Fucked Up I have different kind of weapons in place, which should feel good.
My code for the weapons started simple. When the trigger is pulled launch a bullet, eject a shell, put a flash in front of the gun and make a sound. I thought well yes how complicated can that possibly go? I started to think about reloading, just wait a bit and reload it. Still very simple. But then a double barrel shotgun came along the way...
But it always ends up complicated
I started to need a timer and a counter to eject the shells after the second shot and with a delay of at least half a second. The code went out of hand pretty quickly and I was close to something but couldn't make it work without breaking other stuff. And after some refactoring and machine gun later I started to think about how I could fix the mess at hand.
Just for a comparsion here my old code
and this was without reloading and it ejected the shell after every shot. But I wanted a double barrel shot gun and that ejects two shells after the second shot with a delay.
I used behavior tree to model my very simple and super stupid soldiers. And I thought well why not use behavior tree for my weapon behavior?
It took me some time to get my head around the behavior tree idea. Basically you break everything up in small tasks. Tasks can either FAIL, be SUCCEED or be still RUNNING (it stays there). The behavior tree gets executed every frame, like the whole tree gets exectuted.
You have either a sequence which runs its children as long none FAILs. A sequence which gets SUCCEED from all children will return SUCCEED else FAIL.
Or you have a selector which runs its children as long none return SUCCEED. It returns SUCCEED if one child returns SUCCEED else FAIL if none SUCCEED.
Check out this article to get a better understanding what behavior trees are Behavior trees for AI: How they work
Let's see the code of the double barrel shotgun with proper shell ejection and reloading
Looks pretty neat doesn't it? It is straight forward. It has two possible main tasks "reload" and "shoot".
In case the ammo count is zero it initates a reload after waiting 1.4 seconds (pretty quick reload for a double barrel shotgun).
Else it checks if the trigger is pulled and launchs the projectils and waits until the trigger gets released. In case the ammo count is zero I wait 0.6 seconds and eject 2 shells.
This is it. The code is much simpler, maintainable, reusable, testable and surprisingly stable. In the beginning I thought behavior trees only for NPCs, I never thought this could be so handy for other behavior stuff in my game. But it is, not just weapons.
I hope you enjoyed the article and I could give you some new inputs.