• 🏆 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!

Would this leak?

Status
Not open for further replies.
Level 20
Joined
Jul 6, 2009
Messages
1,885
function Question takes title t returns question
call AskQuestion(t)
JASS:
function Closest_Unit takes group g,location l returns unit
    local real r
    local real dx
    local real dy
    local unit u1
    local unit u2
    set r = 1000
    loop
        set u1 = FirstOfGroup(g)
        exitwhen u1 == null
        set dx = GetUnitX(u1) - GetLocationX(l)
        set dy = GetUnitY(u1) - GetLocationY(l)
        if r > SquareRoot(dx * dx + dy * dy) then
            set u2 = u1
            set r = SquareRoot(dx * dx + dy * dy)
        endif
        call GroupRemoveUnit(g,u1) 
        set u1 = null
    endloop
    return u2
endfunction
Would this function leak local unit u2?
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Yes. The way around it is to use a global variable instead of a local one, like this.

JASS:
globals
    unit closestUnitResult = null
endglobals


function Closest_Unit takes group g,location l returns unit
    local real r
    local real dx
    local real dy
    local unit u1
    set r = 1000
    loop
        set u1 = FirstOfGroup(g)
        exitwhen u1 == null
        set dx = GetUnitX(u1) - GetLocationX(l)
        set dy = GetUnitY(u1) - GetLocationY(l)
        if r > SquareRoot(dx * dx + dy * dy) then
            set closestUnitResult = u1
            set r = SquareRoot(dx * dx + dy * dy)
        endif
        call GroupRemoveUnit(g,u1) 
        set u1 = null
    endloop
    return closestUnitResult
endfunction

There are more efficient ways of doing this, though. It will take a few minutes I'll give you an example.

JASS:
library ClosestUnitLib initializer init

//##############################################################################################
globals
    private unit        result          = null
    
    private group       ENUM__grp       = CreateGroup( )    
    private boolexpr    ENUM__filter    = null              // Both ENUM__filter and ENUM__func 
    private code        ENUM__func                          // reference the same function, but 
    private real        ENUM__distance                      // in order to pass them to the     
    private real        ENUM__x                             // necessary functions they must be 
    private real        ENUM__y                             // in specific format.
    
endglobals


//##############################################################################################
private function enumfilter takes nothing returns boolean
    local unit e = GetFilterUnit( )
    local real x = GetUnitX(e)
    local real y = GetUnitY(e)
    local real d = (x-ENUM__x)*(x-ENUM__x) + (y-ENUM__y)*(y-ENUM__y)
    if d < ENUM__distance then
        set ENUM__distance = d
        set result = e
    endif
    set e = null
    return false
endfunction
private function enumfunc takes nothing returns nothing
    local unit e = GetEnumUnit( )    
    local real x = GetUnitX(e)
    local real y = GetUnitY(e)
    local real d = (x-ENUM__x)*(x-ENUM__x) + (y-ENUM__y)*(y-ENUM__y)
    if d < ENUM__distance then
        set ENUM__distance = d
        set result = e
    endif
    set e = null
endfunction


//##############################################################################################
function GetClosestUnit takes real x, real y, real range returns unit
    set ENUM__x = x
    set ENUM__y = y
    set ENUM__distance = range*range
    call GroupEnumUnitsInRange(ENUM__grp, x, y, range, ENUM__filter)
    
    return result
    
endfunction
function GroupGetClosestUnit takes group g, real x, real y returns unit
    local unit f = FirstOfGroup(g)
    set ENUM__x = x
    set ENUM__y = y
    set x = GetUnitX(f)
    set y = GetUnitY(f)
    set ENUM__distance = (x-ENUM__x)*(x-ENUM__x)+(y-ENUM__y)*(y-ENUM__y)
    set result = f
    call ForGroup(g, ENUM__func)
    
    set f = null
    return result

endfunction


//##############################################################################################
private function init takes nothing returns nothing
    set ENUM__func   = function enumfunc
    set ENUM__filter = Filter(function enumfilter)
    
endfunction


endlibrary

So first of all, you can eliminate a couple of SquareRoot( ) calls. They are not necessary when you're merely comparing which of two values is closer. Second of all I used direct coordinates x and y instead of a location, which will save native calls where they are not necessary. You shouldn't do set r = 1000 either or you will be assuming that the closest unit will never be more than 1000 units away.

JASS:
    local unit f = FirstOfGroup(g)
    set ENUM__x = x
    set ENUM__y = y
    set x = GetUnitX(f)
    set y = GetUnitY(f)
    set ENUM__distance = (x-ENUM__x)*(x-ENUM__x)+(y-ENUM__y)*(y-ENUM__y)
    set result = f
    call ForGroup(g, ENUM__func)

What I've done here is set ENUM__distance to the distance of an arbitrary unit from the group (represented by "f"). In the case that "f" is in fact the closest unit in the group, then the function will still be safe because I have performed set result = f.
 
Last edited:
Status
Not open for further replies.
Top