top of page

Damage Distribution Curve

Background

Most of the attacks launch a bunch of particles into an enemy's "soul".  Whenever one of the particles hits the enemy, it deals damage to him.

3ce0636e-be8c-4996-a25f-eaa21d66ea26.gif

Goal

Find a function that associates a number of particles that hit the soul with the total damage they deal.

Result

Found a suitable function. It is: 

функция.png
4d.png

where x is the number of particles that actually hit the soul;

n is the total number of particles;

t is the number of particles we expect to hit the soul in most cases;

D is the expected damage in case t particles will hit the soul.

Solution

The first important insight was that the damage distribution function should consider that some small amount of particles can occasionally miss and that fact should not be crucial to the amount of damage done to the target. Likewise, if a player fails to dodge some particles he was supposed to, that also should not affect the damage greatly. This requirement is important because, without it, the game would be not about strategy but about dodging the particles. To reduce the impact of a player's bullet-hell skill, we must allow the player to make mistakes sometimes.

diff.png

That said, the function we need should look something like this:

desire.png

It is easy to notice that the arcsin function is very similar:

arcsin.png

Suppose we know the damage which should be dealt if all the particles hit the target (d) and the number of the particles (p). Let's move the arcsin function and scale it. It can be done using linear transformation:

trans.png
2f.png
1f.png
3f.png

The function we got is OK, but it would be better if it was steeper in the middle. This can be achieved by dividing by some function of x. This denominator function determines how much the values will be decreased depending on their position in our interval.


To make things simple, let's consider only the left half of our function for a while. As we want to make our function steeper in the middle, the denominator should raise from k to 1 as we're approaching the point x = n/2. For simplicity, let's use a linear function as a denominator. It is listed below:

gendenominator.png

There, k is a measure of how much steeper we want the function to become. It can have values from 0 to 1; the less the value is, the steeper is the function. By experimenting with values, I've found the value that suits my purposes: k = 0.5. The denominator then becomes:

denominator.png

After the division the function becomes:

dividedfunc.png

As we considered only the left half of our function, when we try to divide it by the denominator found, the right part is corrupted. Yet, this problem is easy to solve. We want our function to be symmetrical in the middle, so let's just take the left half, reflect it and turn it upside down. The transformation used is listed below:

transform1.png
t1.png
transform2.png
t2.png

After that transformation the function becomes:

transformedfunc.png

This formula can be used when we expect half of the particles to hit the target. But what if the most probable amount of the particles, that hit the enemy is 3, 8 or n/3? In that case, we can resize the parts of our function to move the former medium wherever we like. Once again, we apply linear transformations. Let t be the expected number of the particles. The result is:

tfunc.png

The formula for the right part of the function can be simplified:

simplifiedright.png

Here's what we get for different values of t - expected hit count:

funcgif.gif

At this point, the total damage (d) becomes meaningless. What makes sense is d/2, the expected damage at t hits. Let's rename d/2 as D. The total damage should be equal to D*n/t. We need to make the final adjustments to the right part of our function to suit this requirement. That's easy, just divide the subtrahend by D, multiply by (D*n/t - D) and replace minuend with D*n/t:

функция.png
4d.png

That's it! Here's how our curve looks like:

finalfunc.gif
bottom of page