Your cart is currently empty!
How to Get Perfect Spray Patterns in Godot.
In my opinion spray patterns are what separate the men from the boys. Are you going to spray your foes down, or be praying in the corner wanting to go back to Halo… Just kidding, I love halo.
If you’re crazy like me. Or perhaps you were working on an FPS game and you noticed how unrealistic it is to have a laser weapon. Tackling spray patterns was one of the first things I did after getting the basics up and running.
When I was designing my FPS controller the first gun I added after the pistol was an m16 or AR of some kind. It was the first time working with an automatic style weapon and it became painfully obvious early on that without recoil or spray patterns a hit scan weapon just isn’t fun.
You see Hitscan weapons have no lead time, the minute you pull the trigger a hit is registered where ever it lands. Which is fine for a video game. But with no spray or recoil it makes it a lot harder for the person being shot at to avoid anything.
There’s also an added skill cap to the game with recoil. A player has to learn to control the weapon. That is if the pattern remains consistent.
The very first thing I tried in my game was generating a random number between 0 and 1 and adding it to the x and y axis of my ray cast. This got the job done visually but being random meant that it gave the player little to learn about controlling it.
In my opinion a spray pattern that travels in a straight line isn’t as interesting or challenging to control. And if the pattern is too random then it’s frustrating if you miss your shots. Since you have less control. Recoil is only fun if the player can master it.
But how do you get consistent spray patterns? Well, I experimented with using patterns generated with code. And it worked. It was consistent. But I was using the weapons stats to calculate the pattern and it meant if I didn’t like the pattern I had to change things like the ammo capacity and fire rate. Then on top of that, they didn’t vary that much. I don’t know, maybe I’m just bad at math.
So I gave up. And Decided to do it the hard way. I with a big fat list of Vectors. This works okay but it kind of sucked having to map everything out.
Then I thought. I need to combine the two. I can keep the vector list buuuut I’ll use a classic formula from high school to control the increase in distance between shots.
The formula I’m talking about: Pythagorean theorem.
Now. Do we really have to open old wounds like that? Unfortunately yes. Also don’t worry we all had out fair share of cringe. Especially me. So let’s try to focus on the math rather than all of unresolved trauma of your teenage years… or is that Just me.
So I’m sure we all remember that spiral thingy from highs school. For some reason that popped into my head when working on all of this. It’s called the Spiral of Theodorus.
Any the incrementally increase in the spiral is just what I needed to control the spread.
I can use the hypotenuse to calculate an increase in amplitude of the spray. Each shot we’ll store the hypotenuse in a variable and on the next shot use the result to recalculate another Hypotenuse. This increases the hypotenuse variable every shot which is multiplied by the vector map and emitted out as a signal for the player controller and ray cast. We can use the a side of the triangle to control the amount that the hypotenuse will increase each time.
This way my vector list can just be something small like 0,1 for up and -1,1 for diagonal right. It meant I didn’t have to worry about manually imputing the increase in spread over time. It would just happen naturally and look great. It made tweaking the spray amount easy because all I had to do was increase the “a” side of the triangle and naturally the spray would spread further.
To demonstrate this effect I’m made a new gun called the Theodorus that has spray vector that simply draws a circle.
See how the gun’s spray makes it’s way outward. This is the exact same thing you see in those spirals. And my spray map is just one’s and zeros. This let’s me focus on defining the direction of the spray and not have to worry about the amplitude of the spray. I added a modifier to increase the base, that is the a on the theodorus spiral which in turn increase the amplification of the spray.
It was also helpful for when I when I wanted to add and increase in spread from movement, I simply add a modifier that will increase the “a” temporally when movement was occurring which would push the players gun further into the sky.
I also discovered a cool trick for counting through the array indefinitely so as an added bonus you don’t even need to have a matching number of vectors in the spray array. For example the pistol only has three, even though it has 13 rounds. It’s got a very small spray effect and it doesn’t need to be overly complicated and it’s not automatic so it gets reset a lot more often the automatic weapons so it doesn’t need a massive spray vector. So this is a really handy addition for less complicated weapons where you still want a little kick but it can repeat since it won’t be visually obvious.
Okay so after all that math, we have a signal being sent out up the tree to the kinematic character. Right now the character is responsible for handling the mouse input so it interacts a lot with the guns, which are their own class.
It receives the signal and so does the ray cast that is actually aiming. We add the spray calculation to the x and y of the ray cast every shot. With the theodorus spiral that number increases a little and we’re adding every shot so it pushes further and further every shot.
Then on the character we’re also rotating the camera on a smaller scale by the same spray vector with a sprinkle of randomness thrown in, But not too much, just enough to have tiny variation here and there. This gives a little more amplification to the spray as rotating the camera also moves the Aim ray cast that calculates the hit.
We store the location of the camera as the shooting begins then, when the shooting ends we tween it back to that same spot. We also reset the ray cast back to 0 on both x and y.
If you put all of these together you get a fairly convincing spray pattern that can be easily tweaked to look like anything you want. Here the AK47 is mimic the spray pattern from CS Go.
And here the AR-15 is mimicking the spray pattern of the Vandal from Valorant.
Okay, So that;s how I’m doing recoil in my FPS game. What do you think? Does it need tweaking or do you think this is good enough to work with for now.
Watch the Devlog on Youtube!
Download the FPS Template
Leave a Reply