HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Knockback efficiency

10-16-2007, 11:39 AM#1
Themerion
As you may have noticed from my previos posts; I like to think about efficiency.

Regarding linear knockback!

The most common way to perform a standard knockback is something like the following:
Collapse JASS:
function Knock takes unit u, real angle, real speed, real time returns nothing
    local integer x=Cos(a)*speed
    local integer y=Sin(a)*speed
 // Yeah, some people like to store just the value of Sin(a), then multiplying it in each loop. That's too an option.

 // Now we have the x and y speed, and can begin the looping

 // Initiate the loop and run it!
 // etc, etc.
endfunction

function Trig_Action takes nothing returns nothing
    local unit u=GetSpellAbilityUnit()
    local unit u2=GetSpellTargetUnit()
    call Knock(u2,Atan2(GetUnitY(u2)-GetUnitY(u),GetUnitX(u2)-GetUnitX(u),600,1.5)
    set u2=null
    set u=null
endfunction

As you know, this requires three trigonometric calls. We also calculate an angle which is only used for getting other values. In case of a linear movement (where the angle is constant), we don't really want the angle.

I played around with some maths; and came up with this idea instead:
Zoom (requires log in)

I wonder, would this be faster than the usual angle-trigonometric approach?

Collapse JASS:
function Knock takes real dx, real dy, real speed, real dur returns noting
    local real r
    local real x
    local real y

    if dy==0 then
// Yeah, should never happen. But let's do this properly :)
        set x=speed
        set y=0
    else
        set r=dx/dy
        if dy<0 then
            set y=-1/SquareRoot(1+r*r)
        else
            set y=1/SquareRoot(1+k*k)
        endif

        if dx<0 then
            // Pythagoras'
            set x=-SquareRoot(speed*speed-y*y)
        else
            // Pythagoras'
            set x=SquareRoot(speed*speed-y*y)
        endif
    endif

 // Now we have the x and y speed, and can begin the looping

// Now it's the same as the trig-version.
 // Initiate the loop and run it!
 // etc, etc.
endfunction

function Trig_Actions takes nothing returns nothing
    local unit u=GetSpellAbilityUnit()
    local unit u2=GetSpellTargetUnit()
    call Knock(u2,GetUnitX(u2)-GetUnitX(u),GetUnitY(u2)-GetUnitY(u),600,1.5)
    set u2=null
    set u=null
endfunction
Attached Images
File type: pnglinear movement.png (27.7 KB)
10-16-2007, 05:44 PM#2
TaintedReality
Square root is SLOW. You should do what you suggested:

Quote:
// Yeah, some people like to store just the value of Sin(a), then multiplying it in each loop. That's too an option.

That is the fastest, as far as I know. Less calculations each loop.
10-16-2007, 06:02 PM#3
Silvenon
function Knock takes unit u, angle a, speed v, time t returns nothing

Should be:

function Knock takes unit u, real angle, real speed, real time returns nothing

Otherwise those parameters look like structs :)

local unit u=GetSpellAbilityUnit() = local unit u=GetTriggerUnit()

This is totally off-topic, I know, but I just couldn't resist......
10-16-2007, 09:42 PM#4
Themerion
Quote:
Originally Posted by TaintedReality
Square root is SLOW. You should do [the trig way]

I think that Sin and Cos and Atan2 ought to be just as slow as SquareRoot. And I only use 2 SquareRoots, whilest the angle-approach requires three trig-calls. (I am assuming this. If it turns out that SquareRoot is slower than trig-funcs, then fine)

Quote:
That is the fastest, as far as I know. Less calculations each loop.

Yeah, when using Sin and Cos, the fastest version is to store the xspeed per period values, like this:
Collapse JASS:
call SetArrayReal(myArray,myArrayIndexForXSpeed, Cos(angle)*speed*timer_updateInterval )
10-17-2007, 12:31 AM#5
TaintedReality
Quote:
I think that Sin and Cos and Atan2 ought to be just as slow as SquareRoot. And I only use 2 SquareRoots, whilest the angle-approach requires three trig-calls. (I am assuming this. If it turns out that SquareRoot is slower than trig-funcs, then fine)

Why 3? (I might just be forgetting something). I'm not really sure whether SquareRoot or the trig-funcs are slower, but why not just use the other method?
10-17-2007, 01:05 AM#6
Blackroot
Square root is very slow. I think even directly calling PolarProjectionBJ would be faster then SquareRoot*2. However, I can't say for sure. Also, if both dx and dy are > 0, aren't you calling four square roots? (Or is that not possible? Haven't looked over the calling code.)
10-17-2007, 01:12 AM#7
grim001
It doesn't even matter how fast or slow the initial function is, just precache the cos/sin and use an array lookup in the callbacks, that's as fast as it's gonna get.
10-17-2007, 02:20 AM#8
PipeDream
Measurements on my machine, an Athlon 64 4400+, 1stddev error bars are all at +-5us.
Calling empty native: 29us
Calling sin: 30us
Calling sqrt: 30us
Multiplying two numbers: 40us
Setting a global real: 20us
Calling empty JASS function: 18us
Attached Images
File type: pngtiming.png (8.5 KB)
10-17-2007, 04:59 AM#9
Blackroot
Sin and Sqrt have the same speed. Interesting. Is this method possibly faster for moving targets?
10-17-2007, 08:08 PM#10
Themerion
Quote:
Originally Posted by grim001
It doesn't even matter how fast or slow the initial function is, just precache the cos/sin and use an array lookup in the callbacks, that's as fast as it's gonna get.

It doesn't matter much, that's right. However, if this method actually is a little bit faster==better, then why not use it instead?

As I showed in the code; with both methods I could "precache" the x-speed and the y-speed. That's the point of this thing. It generates the same data.

Quote:
Originally Posted by Blackroot
Also, if both dx and dy are > 0, aren't you calling four square roots? (Or is that not possible? Haven't looked over the calling code.)

Nah, my method will always run two SquareRoot-functions (unless dy==0). It's controlled by a simple if-then-else.

Quote:
Originally Posted by PipeDream
Measurements on my machine, an Athlon 64 4400+, 1stddev error bars are all at +-5us.
Calling empty native: 29us
Calling sin: 30us
Calling sqrt: 30us
Multiplying two numbers: 40us
Setting a global real: 20us
Calling empty JASS function: 18us

These results are staggering... Multiplying a real with itself is ~33% slower than running a Sin or SquareRoot function? Calling a Sin function is ~50% than setting a variable?

Perhaps I have to rethink my scripting.

Huge thanks Pipe!
10-17-2007, 11:48 PM#11
PipeDream
Multiplication isn't slow, there are just more operations to loading two variables and acting on them.
10-17-2007, 11:54 PM#12
grim001
Quote:
Originally Posted by Themerion
It doesn't matter much, that's right. However, if this method actually is a little bit faster==better, then why not use it instead?

1.) it's ugly and longer
2.) it makes no difference at all
10-18-2007, 01:46 AM#13
emjlr3
interesting numbers Pipe...
10-18-2007, 01:49 PM#14
Themerion
Quote:
Originally Posted by grim001
1.) it's ugly and longer
2.) it makes no difference at all

1. Yes it's longer. Calling it ugly is almost an insult; so please don't.

2. That's why I posted this. I wanted to know if it made any difference. PipeDream has provided data which makes me think that it does not.