HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Skill lags the game when used often

02-16-2010, 08:55 PM#1
Saishy
I kept spamming a backflip skill that I did for fun, but after a few tries the game became unplayable, the more I used, more slow the entire game got.

Collapse JASS:
scope Backflip initializer Init_backflip

globals
    private integer BF = 'A04P'
    private integer TIMES = 20
    private real MOVE = 25
    private real TIMER = 0.03
    private real TREERADIUS = 120
endglobals

private struct backflipstruct
    unit caster
    integer times
    real x
    real y
    real angle
endstruct

function backflip_Conditions takes nothing returns boolean
    return (GetSpellAbilityId() == BF)
endfunction

function backflip_Move takes nothing returns nothing
    local backflipstruct bf = GetTimerData(GetExpiredTimer())
    set bf.x = bf.x + MOVE * Cos(bf.angle)
    set bf.y = bf.y + MOVE * Sin(bf.angle)
    
    call DestroyTree(bf.x, bf.y, TREERADIUS)
    call SetUnitPosition(bf.caster, bf.x, bf.y)
    
    set bf.x = GetUnitX(bf.caster)
    set bf.y = GetUnitY(bf.caster)

    set bf.times = bf.times + 1
    if (bf.times == TIMES) then
        call PauseUnit(bf.caster, false)
        call SetUnitAnimation(bf.caster, "stand")
        call SetUnitTimeScale(bf.caster, 1.)
        call SetUnitInvulnerable(bf.caster, false)
        set bf.caster = null
        call ReleaseTimer(GetExpiredTimer())
        call bf.destroy()
    endif
endfunction

function backflip_Actions takes nothing returns nothing
    local backflipstruct bf = backflipstruct.create()
    local timer t
    set bf.caster = GetTriggerUnit()
    set bf.x = GetUnitX(bf.caster)
    set bf.y = GetUnitY(bf.caster)
    set bf.angle = (180 + GetUnitFacing(bf.caster)) * bj_DEGTORAD
    set bf.times = 0
    call PauseUnit(bf.caster, true)
    call SetUnitAnimationByIndex(bf.caster, 9)
    call SetUnitTimeScale(bf.caster, 1.5)
    call SetUnitInvulnerable(bf.caster, true)
    
    set t = CreateTimer()
    call SetTimerData(t, bf)
    call TimerStart(t, TIMER, true, function backflip_Move)
endfunction

//===========================================================================
function Init_backflip takes nothing returns nothing
    local trigger trg_backflip = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trg_backflip, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trg_backflip, Condition(function backflip_Conditions))
    call TriggerAddAction(trg_backflip, function backflip_Actions )
    set trg_backflip = null
endfunction

endscope
02-16-2010, 09:18 PM#2
Michael Peppers
Maybe it's because you're using CreateTimer() instead of NewTimer(), give it a shot.
02-16-2010, 09:34 PM#3
Fireeye
I found only 1 issue may causing it.
1. You use CreateTimer(), it has to be NewTimer() when using TimerUtils.
And 1 unknown thing, it's the function DestroyTree(). Can not say if it's a possible issue or not.
Also please use the JASS tag when you're not posting GUI Triggers.
However beside those 2 things i've not really found any reason why it should cause any sort of lag.
Took the time to re-write the script and make it a bit more readable.
Collapse JASS:
scope Backflip
    globals
        private constant integer BF = 'A04P'
        private constant integer TIMES = 20
        private constant real MOVE = 25
        private constant real TIMER = 0.03
        private constant real TREERADIUS = 120
    endglobals
    private struct backflip
        unit caster
        integer times
        real x
        real y
        real angle
        method onDestroy takes nothing returns nothing
            //Reseting times counter
            set .times = 0
            //minor leak (they're very minor ...)
            .caster = null
        endmethod
        static method condition takes nothing returns boolean
            //Returning boolean value of cast
            return GetSpellAbilityId() == BF
        endmethod
        static method callback takes nothing returns nothing
            //Getting struct attached to timer
            local backflip bf = backflip(GetTimerData(GetExpiredTimer()))
            //Updating Coordinates
            set bf.x = bf.x + MOVE * Cos(bf.angle)
            set bf.y = bf.y + MOVE * Sin(bf.angle)
            //Destroying any tree near ... ?
            //Can not check this function
            call DestroyTree(bf.x, bf.y, TREERADIUS)
            //Setting caster location, notice SetUnitX/Y will ignore pathing
            call SetUnitPosition(bf.caster, bf.x, bf.y)
            //Updating coordinates in case of getting blocked
            set bf.x = GetUnitX(bf.caster)
            set bf.y = GetUnitY(bf.caster)
            //increasing times counter
            set bf.times = bf.times + 1
            //When it hits the limit, pause + clean up
            if (bf.times == TIMES) then
                //Unpause of the caster
                call PauseUnit(bf.caster, false)
                //Resetting it's animation
                call SetUnitAnimation(bf.caster, "stand")
                call SetUnitTimeScale(bf.caster, 1.)
                //Making caster vulnerable
                call SetUnitInvulnerable(bf.caster, false)
                //Releasing Timer
                call ReleaseTimer(GetExpiredTimer())
                //Destroying struct
                call bf.destroy()
            endif
        endmethod
        static method cast takes nothing returns nothing
            //Creating a new struct on cast
            local backflip bf = backflip.create()
            //Getting a new timer from timerutils
            local timer t = NewTimer()
            //Assigning caster to struct
            set bf.caster = GetTriggerUnit()
            //Storing location of caster
            set bf.x = GetUnitX(bf.caster)
            set bf.y = GetUnitY(bf.caster)
            //Getting angle of facing and add bj_PI
            set bf.angle=(GetUnitFacing(bf.caster)*bj_DEGTORAD)+bj_PI
            //Pausing caster and making it invulnerable
            call PauseUnit(bf.caster, true)
            call SetUnitInvulnerable(bf.caster, true)
            //Setting animation index
            call SetUnitAnimationByIndex(bf.caster, 9)
            call SetUnitTimeScale(bf.caster, 1.5)
            //Attaching struc to timer
            call SetTimerData(t,integer(bf))
            //Starting timer
            call TimerStart(t, TIMER, true, function backflip.callback)
            //Cleaning minor leak
            set t = null
        endmethod
        static method onInit takes nothing returns nothing
            //Creating a new trigger
            local trigger tr = CreateTrigger()
            //Adding event
            call TriggerRegisterAnyUnitEventBJ(tr, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            //Adding condition
            call TriggerAddCondition(tr, Condition(function backflip.condition))
            //Adding action
            call TriggerAddAction(tr, function backflip.cast)
            //Cleaning minor leak
            set tr = null
        endmethod
    endstruct
endscope
---EDIT---
Darn you Peppers xD

---EDIT2---
Q: (And lol, do you really think a full struct is better legible? I'm confused o.o)
A: I prefer using structs to organize things, especially if you got different structs in the same scope/library.
02-16-2010, 09:46 PM#4
Saishy
I edited my post as soon as I posted it to change to JASS tags, it only had 2 views (one mine, and you probably saw the thread as soon as it got online)

I don't know how that CreateTimer() got there xD
Thanks for that.

The destroytree function:

Collapse JASS:
private function DestroyTreeEx takes nothing returns nothing
    local destructable tree = GetEnumDestructable()
    local real x
    local real y
    local real dist
    if IsDestructableTree(tree) then
        set x = GetDestructableX(tree)
        set y = GetDestructableY(tree)
        set x = x - TreeX
        set y = y - TreeY
        set dist = SquareRoot(x * x + y * y)
        if (dist <= TreeDist) then
            call KillDestructable(tree)
        endif
    endif
    set tree = null
endfunction

function DestroyTree takes real x, real y, real radius returns nothing
    local rect r = Rect(x-radius, y-radius, x+radius, y+radius)
    set TreeX = x
    set TreeY = y
    set TreeDist = radius
    call EnumDestructablesInRect(r, null, function DestroyTreeEx)
    call RemoveRect(r)
    set r = null
endfunction

I didn't post it coz lots of triggers are using it, and only that spell is lagging.
Thanks in advance!

-------------------------------------

Apparently, the spell is not lagging anymore, I spammed it a lot and I can't really detect if there is a slowdown or not.

(And lol, do you really think a full struct is better legible? I'm confused o.o)
02-16-2010, 09:58 PM#5
Michael Peppers
Quote:
Originally Posted by Fireeye
Also please use the JASS tag when you're not posting GUI Triggers.
Why not? It was fun xD

Quote:
Originally Posted by Fireeye
Darn you Peppers xD
lol
02-17-2010, 12:26 PM#6
Tot
Quote:
Originally Posted by Saishy
I edited my post as soon as I posted it to change to JASS tags, it only had 2 views (one mine, and you probably saw the thread as soon as it got online)

I don't know how that CreateTimer() got there xD
Thanks for that.

The destroytree function:

Collapse JASS:
private function DestroyTreeEx takes nothing returns nothing
    local destructable tree = GetEnumDestructable()
    local real x
    local real y
    local real dist
    if IsDestructableTree(tree) then
        set x = GetDestructableX(tree)
        set y = GetDestructableY(tree)
        set x = x - TreeX
        set y = y - TreeY
        set dist = SquareRoot(x * x + y * y)
        if (dist <= TreeDist) then
            call KillDestructable(tree)
        endif
    endif
    set tree = null
endfunction

function DestroyTree takes real x, real y, real radius returns nothing
    local rect r = Rect(x-radius, y-radius, x+radius, y+radius)
    set TreeX = x
    set TreeY = y
    set TreeDist = radius
    call EnumDestructablesInRect(r, null, function DestroyTreeEx)
    call RemoveRect(r)
    set r = null
endfunction

I didn't post it coz lots of triggers are using it, and only that spell is lagging.
Thanks in advance!

-------------------------------------

Apparently, the spell is not lagging anymore, I spammed it a lot and I can't really detect if there is a slowdown or not.

(And lol, do you really think a full struct is better legible? I'm confused o.o)

roots are evil, use square value instead
02-17-2010, 01:30 PM#7
Ammorth
I really doubt SquareRoot() is as slow as you think...
02-17-2010, 01:37 PM#8
Tot
yea, but it can be avoided --> bad
02-17-2010, 01:40 PM#9
moyack
Quote:
Originally Posted by Tot
roots are evil, use square value instead
Don't be prejudice....

But yes, you can make it a little little bit faster doing the square comparison

Collapse JASS:
        if (x * x + y * y <= TreeDist * TreeDist) then
            call KillDestructable(tree)
        endif
02-17-2010, 11:05 PM#10
Ammorth
I thought someone did a test awhile back that shows SquareRoot() about equal in speed to n*n.

As well, it would be better to set a variable to the squared value and use the variable than doing the multiplication for each comparison.
02-17-2010, 11:38 PM#11
Saishy
Quote:
Originally Posted by Ammorth
I thought someone did a test awhile back that shows SquareRoot() about equal in speed to n*n.

As well, it would be better to set a variable to the squared value and use the variable than doing the multiplication for each comparison.
Using another global?
But how, since the distance varies between each tree?

(Thanks guys for the tips)
02-18-2010, 12:15 AM#12
Ammorth
I guess you can't then.

I still think SquareRoot is the least of your problems if the spell is causing lag. PAS 3.0 does over 50 SquareRoot calculations per GetPath call (not including everything else it does). When the test map starts, I have PAS_GetPath on 0.05 second repeating timer without lag. Aswell, I use it every 0.025 seconds for the GPS arrow and no lag.