1
\$\begingroup\$

I aplolgize if my question is unclear, because I don't know how to formulate the problem.

I have a player that can do damage with a weapon. The weapon has a min and max damage. Holding the space bar makes a power bar grow and degrow on time, and the hit is fired when the space bar is released. This kind of mechanics is quite everywhere.

I manage to do that in Unity with a scrollbar, using delta time to add or substract some damage on time. However, my game is networked, and I don't want the user to send to the server the damage done, just that the strike is performed and make the server compute the damage done.

Here is a graph to better explain my requirement :

enter image description here

I don't want to do it with add and substract at every delta time at server side because of potential compute costs at many parallel games, and the desync risk. I need a formula or a simple algorithm to get the damage at hit time based on time.

Thanks for any help.

\$\endgroup\$
  • 1
    \$\begingroup\$ Just keep in mind that there will be a few ms of latency between client and server and that this latency might not be constant all the time. \$\endgroup\$ – Philipp Jan 11 '18 at 10:12
3
\$\begingroup\$
int delta = end_time - start_time;
delta = delta % period; // period is the time to repeat the entire pattern
if(delta < time_to_top){
    damage = base + rising_slope * delta;
} else {
    damage = base + falling_slope * (period - delta);
}

The key here is the modulo operation (operator %) that will let you grab where in the cycle the attack button was released. Then you can just pretend the player released the button in the first cycle.

\$\endgroup\$
  • \$\begingroup\$ This was my assumption to simplify the approach as well. This is one of those rare questions where it actually has two answers. You can do the true calculations, or you can simplify by taking the mod of the frequency as you described. \$\endgroup\$ – Stephan Jan 15 '18 at 20:10
3
\$\begingroup\$

You should determine a time based function for damage. Wave functions are well established and allow you to generate a result based on time held without any multi-frame calculations

https://stackoverflow.com/a/1073634

This answer contains several formulas and explanations for common functions. For general use, I recommend changing the function's amplitude to 1.

Triangular Wave:
y = abs((x++ % 6) - 3);
This gives a triangular wave of period 6, oscillating between 3 and 0.

Square Wave:
y = (x++ % 6) < 3 ? 3 : 0;
This gives a regular square wave of period 6, oscillating between 3 and 0.

Curvy Triangular Wave:
To get a variation of the triangular wave that has curves rather than straight lines, you just need to introduce an exponent into the equation to make it quadratic.

Concave curves (i.e. x^2 shape):
y = (x++ % 6) < 3 ? 3 : 0;
Concave curves (i.e. sqrt(x) shape)::
y = pow(abs((x++ % 6) - 3), 0.5);


Alright, now let's answer your question, I'm going to use a cosine function since it's incredibly simple.

Let's break this down to meet each of your needs.

var power = -cos(time_held * period_speed)

power will start at -1 and oscillate between -1 and 1 until you let go. The speed of the oscillation is determined by period_speed.

That's a start, now adjust the range

var power = power * 0.5f + 0.5f

With this, your power will oscillate between 0 and 1. The value is purely driven by time_held and does not need to recalculated or compounded every frame.

To get your final output you just do a lerp between min and max.

damage = lerp(min_damage,max_damage,power);

Once again, this value is calculated purely based on time. All a server needs to know is how long the button was held.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.