• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Knockback System

Status
Not open for further replies.
Level 3
Joined
Mar 31, 2015
Messages
28
EDIT: I realized I wrote lot more text than decency allows, so, in short: Is there a knockback system that will slide an unit to exact point (i.e. slide exact distance)? Or, how to do math for in this one to achieve just that?

I need a knockback system (because I'm rather too lazy to make it from scratch, despite excellent tutorials available).

I found this one, but it takes parameters as vectors.
It clearly says "This system cannot be used to throw an object to a target location without doing the math yourself" which would be fine if I knew how do that; alas, I can't figure the math I need to get the unit to land on exact point (or be knocked-back to exact point)

So, help with the math - for known unit location and target location - calculate starting speed for use in this system - would be very much appreciated.

Or, alternatively, another system that does the math for me, or explains how, or knocks-back units at fixed speed.

By the way, I figured the following (please ignore the rest if I misunderstood something and failed miserably):

JASS:
// A parameter for controlling the system clock, in seconds. 1/30 runs
        // 30 times per second.
        private static constant real CLOCK_PERIOD

        // What fraction of velocity should be lost with every iteration of
        // ground friction. Note that simulating an abstraction of friction in
        // units per second overflows real precision numbers. Thus, you must
        // adjust this according to your clock period.
        private static constant real FRICTION_ITER_MULTIPLIER=CLOCK_PERIOD

        // The minimum horizontal velocity a unit can be sliding before the
        // system ignores it. A value of CLOCK_PERIOD*30 means the unit will
        // stop sliding when its slide speed reduces past 30 units per second.
        private static constant real MIN_FOR_KNOCKBACK=

I think these are all parameters I need for charge-like ability (i.e. not jump).
Inside the timer function, speed is calculated as:

JASS:
        set tempDat.delX=tempDat.delX*(1.-FRICTION_ITER_MULTIPLIER)
        set tempDat.delY=tempDat.delY*(1.-FRICTION_ITER_MULTIPLIER)

EDIT: Did more math, still didn't figure it out.

After a while, I realized that you can't know both the distance and the time in advance - but you could use one to calculate the other.

Let's say that we want to knock back the unit across the ground, to a point exactly s units away. What starting velocity should the unit have?

As I understand this script, unit starts moving at some speed (given via parameter), let's call that velocity v0, and then decelerates at constant rate, called FRICTION_ITER_MULTIPLIER. Let's call that rate a. Eventually it will slow down to MIN_FOR_KNOCKBACK, and then it will stop. Let's call that final speed vn.
The number of iterations, i.e. the time it will take for that to happen, is unknown. Let's call it n (= time_in_seconds/CLOCK_PERIOD).

In first iteration, unit will move exactly v0 * CLOCK_PERIOD.
In second, it will move an additional v0 * (1-a) * CLOCK_PERIOD units.
In n-th, it will move v0 * (1-a)^n * CLOCK_PERIOD units.

Therefore, total distance unit will slide equals v0 * CLOCK_PERIOD * (1 + (1-a) + (1-a)^2 + ... + (1-a)^n). Knowing the formula for sum of geometric series, and replacing 1-a with r, we arrive at:

s = v0 * CLOCK_PERIOD * (1 - r^(n+1)) / (1-r))

This is a linear equation with two (unknown) variables. To solve it, we need another equation. Let's examine velocity.

The speed starts at v0 and decelerates at the rate of a, until it becomes as low as vn (see above).

In first iteration, speed is v0 * CLOCK_PERIOD.
In second, it is v0 * (1-a) * CLOCK_PERIOD units.
In n-th, it will be vn = v0 * (1-a)^n) * CLOCK_PERIOD units.

Replacing (1-a) with r, we arrive at second equation:

vn = v0 * CLOCK_PERIOD * r^n


We now have two linear equations with two variables. Apply math.

s = v0 * CLOCK_PERIOD * (1 - r^(n+1)) / (1-r))
vn = v0 * CLOCK_PERIOD * r^n

From second one we have:
v0 = vn / (CLOCK_PERIOD * r^n)

And combining the two, we have:

s = (vn / (CLOCK_PERIOD*r^n)) * CLOCK_PERIOD * (1 - r^(n+1)) / (1-r))

Simplifying the fraction, we have

s = (vn / r^n) * (1 - r^(n+1)) / (1-r))

Moving all constants (and known variables) to the left, we have:

s/vn*(1-r) = (1 - r^(n+1)) / r^n)

s/vn*(1-r) = 1/r^n - r


s/vn*(1-r) + r = 1/r^n

1 / (s/vn*(1-
r) + r) = r^n

And from here, we can calculate n as:

n = log(r, 1 / (s/vn*(1-r) + r))


And from here, we can calculate starting velocity, as we now have n:

vn = v0 * CLOCK_PERIOD * r^n


That was a LOT of math for something so "simple" as knocking the damn footman 600 units away. Either I missed something obvious or that much math is actually necessary (I used this for Log).

I made this in jass to test:
JASS:
static method getRushSpeed takes real distance returns real
            local real s = distance
            local real a = FRICTION_ITER_MULTIPLIER
            local real v0
            local real vn = MIN_FOR_KNOCKBACK/CLOCK_PERIOD
            local real r = (1-a)
            local real n = Log(r, 1/(s*a/vn + r))
            set v0 = vn / Pow(r, n)
            return v0
        endmethod

However, it doesn't really work as it calculates wrong. So due to either my misunderstanding of how KnockBack works, or my starting assumptions, or lack of math skills, I didn't solve this. Help?
 
Last edited:
Level 37
Joined
Jul 22, 2015
Messages
3,485
If you want something with friction or 3D knockback, I advise looking for a system in the Spell Section or JASS Section. For a simple "move a unit in a straight line for a fixed distance" effect, you can do this:

JASS:
set x = GetUnitX(u) + KNOCKBACK_SPEED * Cos(angle)
set y = GetUnitY(u) + KNOCKBACK_SPEED * Sin(angle)

call SetUnitX(u, x)
call SetUnitY(u, y)
set distanceTraveled = distanceTraveled + KNOCKBACK_SPEED
if distanceTraveled >= MAX_DISTANCE then
    // unit has reached maximum distance
endif

KNOCKBACK_SPEED is self explanatory. It can either be a fixed rate or fixed time.
JASS:
KNOCKBACK_SPEED = 100.00 * PERIODIC_TIMEOUT // unit will move 100 units over 1 second (fixed rate)
KNOCKBACK_SPEED = 15.00 // unit will move 15 units every PERIODIC_TIMEOUT seconds (fixed rate)

KNOCKBACK_SPEED = MAX_DISTANCE / (KNOCKBACK_TIME / PERIODIC_TIMOUT) // no matter the distance, it will take the unit KNOCKBACK_TIME seconds to reach MAX_DISTANCE (fixed time)

angle is whatever the angle you want the unit to move.
MAX_DISTANCE is whatever the maximum distance you want it to travel, such as 600 units.
 
Level 3
Joined
Mar 31, 2015
Messages
28
Thanks for the reply.

That would be useful if I was making my own knockback system.

I don't want to make one myself (if at all possible), I want to use existing system! And, as I said, I found this one. It appears it does a lot fancy stuff, such as deceleration, collision detection, hitting trees, bouncing...

What it doesn't do, is take speed or distance as parameters.

Its API states:

JASS:
Knockback3D.add(unit,real a, real b, real c)
/*Apply vector of size a to unit towards b on the XY plane, and c on the Z axis.*/

What should I pass as parameters, if I want my unit to travel, say, 600 units over 1 second? Or, failing that, 600 units over some unspecified time?

As I understand real b and real c are angles which determine direction and/or flying (for jump-like abilities) but don't affect speed. No problem there, but I still don't know how should I calculate value of first real parameter, if I want the unit to slide a fixed distance...
 
Level 3
Joined
Mar 31, 2015
Messages
28
It doesn't matter what the range of the channel-ability is. What matters are the arguments you put when you call Knockback3D.add().
Yes, of course. I called it with unit, 600, angle, 0.

I mentioned ability as this was my way to test it - if I use ability with 600 cast range and call knockback with 600 as parameter, the unit should end at target point, i.e. where the mouse is (assuming I don't move the mouse after leftclick).

However, it doesn't.

Edit: Here, I made a test map. And a screenshot.
 

Attachments

  • KnockbackTestMap.w3x
    25 KB · Views: 43
  • Screenshot.png
    Screenshot.png
    856.7 KB · Views: 82
Last edited:
Level 18
Joined
Nov 21, 2012
Messages
835
call Knockback3D.add(u,velocity,angle,alpha)
//* velocity: speed in units per second at which to knock the unit back
so your 600.00 is starting speed at which units is knocked back, it's not the distance,
there's no direct way to set distance that unit will travel. Or maybe if you play with all those private constants? I didnt dig deep enough in this system's math to be sure
 

Cokemonkey11

Spell Reviewer
Level 29
Joined
May 9, 2006
Messages
3,534
Hi,

In summary, the discussion here is correct:

* You can't easily make a unit stop sliding at a particular point - that's not what this library is for.
* The comment that says you can do the maths yourself is misleading! There should be a better library for doing what you want.
* Since Knockback3D provides an approximation to friction coefficients (which aren't mathematically accurate), standard equations might not work properly here, even if you did the math. An excellent example of comments being important...

--

In the slight chance that *jumping* to a target point (before bouncing) would be good enough, Knockback3 has this - see demo: GitHub - Cokemonkey11/knockback3-demo

And here's some example code of a good implementation of a missile (which "slides" in a direction and does something when it reaches the target): Cokemonkey11 / war-heroes / source / wurst / event-response / abilities / underlord / AttackUnderlord.wurst — Bitbucket
 
Status
Not open for further replies.
Top