# Increasing Recoil Over Time With 'Diminishing Returns'

I have a recoil system where per shot, the recoil value increases. I want the recoil to increase more quickly for the first 10 or so shots, then settle to a slower increase rate that then remains constant.

I have another value, let's call it "Damping", which dampens screen shake and such. This is required because I have many other related effects like screen shake which increase with the more recoil there is. The lower Damping is, the more it diminishes these effects. So I need Damping to decrease while recoil increases. Unlike Recoil, I need to gradually decrease for the first 10 shots, then the rate of decrease needs to get faster.

The other issue is that I need to adjust these curves depending on the weapons ROF. The lower the ROF, the higher the rate of Recoil increase needs to be (and conversely, the faster the rate of decrease for Damping).

I can do it all manually by multiplying recoil and damping by a factor to increase/decrease them per shot, and change the rates of increase/decrease for every x amount of shots, but this is obviously not ideal as it requires a lot of repetitive code and manual tweaking.

I'm using Unity, C#. I'm doing all the increasing and decreasing in void Update().

What sort of formulas could I use to achieve these two curves? I've tried searching for "recoil curves" and looked at many tutorials for various recoil systems but none really apply to what I am trying to do or how my recoil works.

Whenever I need a formula that describes a curve, and the curve isn't extremely simple to describe with code, I use an Animation Curve. Despite the name, this feature is useful for any kind of 2D curve, not just for animation. The animation curve's Evaluate() function takes in a 'time' (x-axis position) as the input and returns a 'value' (y-axis position); in other words, y = curve.Evaluate(x) is equivalent to the standard mathematical notation for a graph function, y = f(x).

Animation curves have several advantages over coded curves - it's easy to understand the general shape of the curve at a glance, it's easy to make big changes to the curve without having to work out new equations, and the performance is excellent. I prefer to set up the curve so that both axes are normalized; i.e., the minimum value is 0 and the maximum value is 1. You can then normalize your inputs and scale your outputs in script.

[SerializeField] private AnimationCurve recoilCurve;
[SerializeField] private AnimationCurve dampeningCurve;
[Tooltip("Scales Y axis of recoil curve")]
[SerializeField] private float maxRecoil = 10;
[Tooltip("Scales Y axis of dampening curve")]
[SerializeField] private float maxDampening = 1;
[Tooltip("Recoil and dampening stop changing once we've fired this many shots")]
[SerializeField] private int maxShotsFiredThreshold = 30;
[Tooltip("Recoil is higher if the weapon shoots slower than this and lower if the weapon shoots faster than this")]
[SerializeField] private float averageROF = 30;

[SerializeField] private Weapon weapon;
private int shotsFired;

private void Update() {
//ratio of shots fired to max, i.e. our position on the x-axis
float t = Mathf.Clamp01(shotsFired / (float)maxShotsFiredThreshold);
float rofFactor = averageROF / weapon.RateOfFire;

//evaluate gives us the y-coordinate for the given x-coordinate,
//which we then scale from a normalized value to our final value
float recoil = maxRecoil * recoilCurve.Evaluate(t) * rofFactor;
float dampening = maxDampening * dampeningCurve.Evaluate(t) / rofFactor;
}


In this example we define a maximum shots fired threshold (beyond which the curves stop changing). The t variable is our normalized number of shots fired, which we calculate by dividing the number of shots fired so far by the maximum threshold. We use t as the input for the Evaluate() function (meaning it specifies the X value along the curve) and Evaluate() function returns the Y-value for that input. Since we used a normalized range of values for the Y-axis, we then scale the output by maxDamping / maxRecoil, and finally apply the rate-of-fire (ROF) factor.

• HI, thanks for the well thought-out response. I was hoping to do it all in code rather than using something like Animation Curve, so I was hoping for formulas in C# I could use.
– Najo
Sep 22, 2022 at 13:26
• @Najo Is there a reason you'd prefer to use code rather than an animation curve? If you're worried about performance, see here and here Sep 22, 2022 at 18:08
• I would also recommend animation curves over code. Sep 24, 2022 at 16:07