HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

GetNearestUnit()

08-21-2006, 09:47 PM#1
wonder_priest
Okay, made a 'GetNearestUnitMatching()' function for a few spells. Here is the function:

Collapse JASS:
function GetNearestUnitMatching takes real range, location source, boolexpr cond returns unit
 local group g=CreateGroup()
 local location ul
 local unit u
 local unit n
 local real dist
   call GroupEnumUnitsInRangeOfLoc(g,source,range,cond)
    loop
     set u=FirstOfGroup(g)
      exitwhen u==null
       set ul=GetUnitLoc(u)
       set dist=DistanceBetweenPoints(source,ul)
        call RemoveLocation(ul)
       if dist<range then
        set n=u
        set range=dist
       endif
      call GroupRemoveUnit(g,u)
    endloop
     call DestroyGroup(g)
    set ul=null
    set g=null
    set u=null
   return n
endfunction

And here is the quick test:
Trigger:
Kill unit
Collapse Events
Player - Player 1 (Red) skips a cinematic sequence
Conditions
Collapse Actions
Custom script: set udg_unit=GetNearestUnitMatching(100000,Location(0,0),null)
Unit - Kill unit
Set unit = No unit

It works great the first time I press Esc, but after that, it gets all screwy and units won't die when they are in certain areas, or they only die when in the range on certain coordinates. It's really bothering me and I'm not sure why it's happening.
08-21-2006, 10:08 PM#2
PipeDream
Probably because it's hitting dead units and trying to kill them again. You have to explicitly check for GetWidgetLife(u) > .405.
BTW you can fix that set to null leak with a little return bugging.
Add a local integer ni and change the bottom to something that resembles
Collapse JASS:
    set ul=null
    set g=null
    set u=null
    set ni = HtoI(n)
    set n = null
    return ni
    return null
endfunction
08-21-2006, 10:17 PM#3
wonder_priest
Quote:
Originally Posted by PipeDream
Probably because it's hitting dead units and trying to kill them again. You have to explicitly check for GetWidgetLife(u) > .405.
BTW you can fix that set to null leak with a little return bugging.
Add a local integer ni and change the bottom to something that resembles
Collapse JASS:
    set ul=null
    set g=null
    set u=null
    set ni = HtoI(n)
    set n = null
    return ni
    return null
endfunction

Ah thanks. Can't believe I forgot to skip dead units, especially when I just did a corpse explosion spell >_>.

And I was wondering about the return leak, do I have to return an integer now, and yeah,,,I can't grasp it I'm brain dead now...

ADD: Okay, now it works once, then it killed a unit when there was obviously another unit closer to the center(floating text at center). Then after those two, it no longer killed any of the units. This is really bugging me now...
08-21-2006, 10:31 PM#4
aquilla
you could also try either adding takes unit n and always pass it as null, or set a global used by blizzard.j (bj_lastCreatedUnit etc) to n and return it instead

using x, y values instead of locations might also be a good idea, if you feel like improving
08-21-2006, 10:43 PM#5
wonder_priest
>>you could also try either adding takes unit n and always pass it as null, or set a global used by blizzard.j (bj_lastCreatedUnit etc) to n and return it instead

I don't see how this would fix the annoying bug :(

>>using x, y values instead of locations might also be a good idea, if you feel like improving
Locations are faster :)
08-21-2006, 10:57 PM#6
aquilla
H2I is much slower than just doing this
Collapse JASS:
    set bj_lastCreatedUnit = n
    set n = null
    return bj_lastCreatedUnit
endfunction


You hadn't edited your post when I read the thread, try using a lower value for range.


ok, how could locations possibly be faster? first you create a location, hen you pass DistanceBetweenPoints() , which you'll see is a bj function that uses GetLocationX/Y to do the calculation, then you destroy the location
08-21-2006, 11:09 PM#7
wonder_priest
Quote:
Originally Posted by aquilla
ok, how could locations possibly be faster? first you create a location, hen you pass DistanceBetweenPoints() , which you'll see is a bj function that uses GetLocationX/Y to do the calculation, then you destroy the location

Locations are still faster, just maybe not in this function . Tell the truth, I didn't want to spend more than 2 minutes on this, so I used locations and a bj >_>. I'll fix now.
08-24-2006, 03:10 PM#8
wonder_priest
Okay, I got really annoyed so I just remade the function.

Collapse JASS:
function GetNearestUnitMatching takes real sourceX, real sourceY, real range, boolexpr cond, boolean considerdead returns unit
 local group g=CreateGroup()
 local unit current
 local unit nearest
 local real currentX
 local real currentY
 local real dist
 
   call GroupEnumUnitsInRange(g,sourceX,sourceY,range,cond)
    
    loop
     set current=FirstOfGroup(g)
      exitwhen current==null
      
        set currentX=GetWidgetX(current)-sourceX
        set currentY=GetWidgetY(current)-sourceY
        set dist=SquareRoot(currentX*currentX+currentY*currentY)
       
         if dist<=range then 
          set range=dist
           
           if considerdead==false and GetWidgetLife(current)>0 then
            set nearest=current
          
           else
            set nearest=current
           
           endif 
        
         endif
       
          call GroupRemoveUnit(g,current)
     endloop 
     
     set bj_lastHauntedGoldMine=nearest
     
     call DestroyGroup(g)
     
     set g=null
     set current=null
     set nearest=null
     
      return bj_lastHauntedGoldMine
        
endfunction

Trigger:
Untitled Trigger 001
Collapse Events
Player - Player 1 (Red) skips a cinematic sequence
Conditions
Collapse Actions
Custom script: call GetNearestUnitMatching(0,0,1000,null,false)
Unit - Kill (Last Haunted Gold Mine)

It works MUCH better, but it still needs some prodding to get it to work all the time. It seems that if a unit is standing still, nothing happens to it, but when I make it move and press ESC it dies.

So, can someone possibly tell me why it doesn't work 100% of the time, because as of now I don't trust it with triggers that need to function correctly.
08-24-2006, 03:23 PM#9
blu_da_noob
I see no actual bug, but you have something weird there. You set nearest = current whether current is alive or dead (and you must check for GetWidgetLife() > 0.405 for living/dead).

You can also make it more efficient by removing the squareroot. Before your loop, set range = range * range and then remove the SquareRoot function.
08-24-2006, 03:32 PM#10
Rising_Dusk
That bit about the "GetWidgetLife() > 0.405" always intrigued me..
Does that mean checking if "GetUnitState(u, UNIT_STATE_LIFE) > 0" is entirely innaccurate?
Sorry if this seems slightly off-topic, but it just strikes me as odd.
Is .405 the cutoff where WC3 registers a unit as dead?
08-24-2006, 03:32 PM#11
wonder_priest
Quote:
Originally Posted by blu_da_noob
I see no actual bug, but you have something weird there. You set nearest = current whether current is alive or dead
Oops.
Collapse JASS:
           if considerdead==false and GetWidgetLife(current)>0.405 then
            set nearest=current
          
           elseif considerdead
            set nearest=current
           
           endif
Quote:
(and you must check for GetWidgetLife() > 0.405 for living/dead).
Isn't >0 the same as >.405? (for my purposes)


It still doesn't work 100% of the time either way. Maybe someone can put it into a test map, and see if you can find the bug. It would be much appreciated!
08-24-2006, 03:33 PM#12
iNfraNe
I dont see why this function should have the GetWidgetLife() > 0.405 anyway. It should be in the conditionfunc, not inside the function. You may want to get the closest corpse once, and you would not be able to use this func. (Or, you can I just saw, but a boolean for that is... well.. not a good way ithink)

Quote:
Is .405 the cutoff where WC3 registers a unit as dead?
yes.
08-24-2006, 03:35 PM#13
blu_da_noob
Quote:
Originally Posted by Rising_Dusk
Is .405 the cutoff where WC3 registers a unit as dead?

Yes. No idea why, but it is.

Zomg infrane made teh ninja editz!
08-24-2006, 03:37 PM#14
Rising_Dusk
That's so weird...
Oh well, guess I should go update my map to adjust. :/

Thanks you two.

Actually..
Another question.
Does it matter if I use GetWidgetLife(u) or GetUnitState(u, UNIT_STATE_LIFE)?
08-24-2006, 03:41 PM#15
blu_da_noob
No. I would think GetWidgetLife could be a little faster, due to excluding checks to make sure that the handle is a unit, but that is only a possibility. If there is any difference, it is negligible anyway.