- Joined
- Mar 25, 2005

- Messages
- 252

GetClosestUnit(s) v1.3.1

finds the unit, or group of units closest to a point faster than any existing alternative

finds the unit, or group of units closest to a point faster than any existing alternative

**v1.3.1**

- removed unnecessary GroupClear calls

**v1.3**

- GetClosestUnit function is now smart
- GetClosestUnitAlt: a new function that resembles the old and simple GetClosestUnit function (since it can be faster than the smart version in some rare cases)
- GetClosestUnit and GetClosestUnitInRange now use ForGroup() instead of And() making them a lot faster

**v1.2b**

- apparently boolexprs created with And() leak every time they are created, these leaks have now been removed from GCU

**v1.2**

- added a description and comments
- replaced bj_globals with own private globals (again from HINDYhat's request)

**v1.1**

- fixed a few bugs in GetClosestUnit(s)InGroup and also replaced a few global groups with local ones (thx HINDYhat)
- changed library name from GetClosestUnit to GCU

JASS:

```
//==============================================================================
//---DiscipleOfLife's-----------------------------------------------------------
// GCU // GetClosestUnit(s) v1.3.1
//------------------------------------------------------------------------------
//
// This library contains the following functions, each of which return the
// unit that is closest to given coordinates and passes a specified filter:
//
// - GetClosestUnit(x, y, filter)
// - GetClosestUnitAlt(x, y, filter)
// - GetClosestUnitInRange(x, y, radius, filter)
// - GetClosestUnitInGroup(x, y, g)
//
// Included are also the following functions, each of which return a
// group consisting of the units closest to given coordinates that
// pass a specified filter:
//
// - GetClosestUnits(x, y, n, filter)
// - GetClosestUnitsInRange(x, y, radius, n, filter)
// - GetClosestUnitsInGroup(x, y, g, n)
//
// Important:
//
// - flying heights and the height of the ground aren't taken into account,
// only the distance in 2D
//
// - these functions can't be used in the boolexpr's passed to them
//
// - all of the functions in this library go through many units to find the
// closest one, meaning that the functions' performance is highly dependant
// on the amount of units they have to go through
//
//------------------------------------------------------------------------------
library GCU
globals
private unit CurrentPick
private real CenterX
private real CenterY
private real CurrentDistance
private group AnyGroup = CreateGroup()
endglobals
private function Enum takes nothing returns nothing
local unit u = GetEnumUnit()
local real dx = GetUnitX(u) - CenterX
local real dy = GetUnitY(u) - CenterY
local real d = (dx*dx + dy*dy) / 10000.
if d < CurrentDistance then
set CurrentDistance = d
set CurrentPick = u
endif
set u = null
endfunction
//==========================================================================
// Finds the unit that is closest to (x, y) from all units on the map that
// pass the filter and do not have the locust ability.
//
function GetClosestUnit takes real x, real y, boolexpr filter returns unit
local real r = 800.
loop
call GroupEnumUnitsInRange(AnyGroup, x, y, r, filter)
exitwhen FirstOfGroup(AnyGroup) != null
if r >= 3200. then
call GroupEnumUnitsInRect(AnyGroup, bj_mapInitialPlayableArea, filter)
exitwhen true
endif
set r = 2.00 * r
endloop
set CurrentPick = null
set CenterX = x
set CenterY = y
set CurrentDistance = 100000
call ForGroup(AnyGroup, function Enum)
return CurrentPick
endfunction
//==========================================================================
// Does the same as above. Faster when there are no units that pass the
// filter in a 3200 radius, but at other times slower, and most likely a
// lot slower. How much faster is somewhat directly proportional to the
// amount of units that do not pass the filter inside that 3200 radius.
//
function GetClosestUnitAlt takes real x, real y, boolexpr filter returns unit
set CurrentPick = null
set CenterX = x
set CenterY = y
set CurrentDistance = 100000
call GroupEnumUnitsInRect(AnyGroup, bj_mapInitialPlayableArea, filter)
call ForGroup(AnyGroup, function Enum)
return CurrentPick
endfunction
//==========================================================================
// Finds the unit that is closest to (x, y) from all units in the specified
// radius, that pass the filter and do not have the locust ability.
//
function GetClosestUnitInRange takes real x, real y, real radius, boolexpr filter returns unit
set CurrentPick = null
set CenterX = x
set CenterY = y
set CurrentDistance = 100000
call GroupEnumUnitsInRange(AnyGroup, x, y, radius, filter)
call ForGroup(AnyGroup, function Enum)
return CurrentPick
endfunction
//==========================================================================
// Finds the unit that is closest to (x, y) from whichGroup. Unlike the
// other versions this one considers locusted units also.
//
function GetClosestUnitInGroup takes real x, real y, group whichGroup returns unit
set CurrentPick = null
set CenterX = x
set CenterY = y
set CurrentDistance = 100000
call ForGroup(whichGroup, function Enum)
return CurrentPick
endfunction
//==========================================================================
// The following three functions do the same as the preceding ones, with //
// the exception that they return groups consisting of the n closest //
// units instead of the closest unit //
//==========================================================================
globals
private group ResultGroup
endglobals
function GetClosestUnits takes real x, real y, integer n, boolexpr filter returns group
call GroupEnumUnitsInRect(AnyGroup, bj_mapInitialPlayableArea, filter)
set ResultGroup = CreateGroup()
set CenterX = x
set CenterY = y
loop
exitwhen n == 0
set CurrentPick = null
set CurrentDistance = 100000
call ForGroup(AnyGroup, function Enum)
exitwhen CurrentPick == null
call GroupRemoveUnit(AnyGroup, CurrentPick)
call GroupAddUnit(ResultGroup, CurrentPick)
set n = n - 1
endloop
return ResultGroup
endfunction
function GetClosestUnitsInRange takes real x, real y, real radius, integer n, boolexpr filter returns group
call GroupEnumUnitsInRange(AnyGroup, x, y, radius, filter)
set ResultGroup = CreateGroup()
set CenterX = x
set CenterY = y
loop
exitwhen n == 0
set CurrentPick = null
set CurrentDistance = 100000
call ForGroup(AnyGroup, function Enum)
exitwhen CurrentPick == null
call GroupRemoveUnit(AnyGroup, CurrentPick)
call GroupAddUnit(ResultGroup, CurrentPick)
set n = n - 1
endloop
return ResultGroup
endfunction
private function AnyGroupAddGroupEnum takes nothing returns nothing
call GroupAddUnit(AnyGroup, GetEnumUnit())
endfunction
function GetClosestUnitsInGroup takes real x, real y, group whichGroup, integer n returns group
call GroupClear(AnyGroup)
call ForGroup(whichGroup, function AnyGroupAddGroupEnum)
set ResultGroup = CreateGroup()
set CenterX = x
set CenterY = y
loop
exitwhen n == 0
set CurrentPick = null
set CurrentDistance = 100000
call ForGroup(AnyGroup, function Enum)
exitwhen CurrentPick == null
call GroupRemoveUnit(AnyGroup, CurrentPick)
call GroupAddUnit(ResultGroup, CurrentPick)
set n = n - 1
endloop
return ResultGroup
endfunction
endlibrary // End of GetClosestUnit
//==============================================================================a
```

JASS:

```
//==============================================================================
//---DiscipleOfLife's-----------------------------------------------------------
// GCU // GetClosestUnit(s) v1.3.1 without vJass
//------------------------------------------------------------------------------
//
// Contents:
//
// This library contains the following functions, each of which return the
// unit that is closest to given coordinates and passes a specified filter:
//
// - GetClosestUnit(x, y, filter)
// - GetClosestUnitAlt(x, y, filter)
// - GetClosestUnitInRange(x, y, radius, filter)
// - GetClosestUnitInGroup(x, y, g)
//
// Included are also the following functions, each of which return a
// group consisting of the units closest to given coordinates that
// pass a specified filter:
//
// - GetClosestUnits(x, y, n, filter)
// - GetClosestUnitsInRange(x, y, radius, n, filter)
// - GetClosestUnitsInGroup(x, y, g, n)
//
// Notes:
//
// - flying heights and the height of the ground aren't taken into
// account, only the distance in 2D
//
// - these functions can't be used in the boolexpr's passed to them
//
// - all of the functions in this library go through many units to find
// the closest one, meaning that the functions' performance is highly
// dependant on the amount of units they have to go through
//
// - this without vJass version is as efficient as the vJass version
//
// Implementing Instructions:
//
// - either paste this system into your map's header or inside any
// trigger that has been converted to custom text, that has been
// created before any other triggers in which you wish to use these
// functions!
//
// - press Ctrl+B to open the variable editor and create the following
// variables leaving their initial values to the default ones
//
// Type Name
// Unit GCU_CurrentPick
// Real GCU_CurrentX
// Real GCU_CurrentY
// Real GCU_CurrentDistance
// Unit Group GCU_AnyGroup
// Unit Group GCU_ResultingGroup
//
// - congrats, you are done!
//
//------------------------------------------------------------------------------
function GCU_Enum takes nothing returns nothing
local unit u = GetEnumUnit()
local real dx = GetUnitX(u) - udg_GCU_CurrentX
local real dy = GetUnitY(u) - udg_GCU_CurrentY
local real d = (dx*dx + dy*dy) / 10000.
if d < udg_GCU_CurrentDistance then
set udg_GCU_CurrentDistance = d
set udg_GCU_CurrentPick = u
endif
set u = null
endfunction
//==========================================================================
// Finds the unit that is closest to (x, y) from all units on the map that
// pass the filter and do not have the locust ability.
//
function GetClosestUnit takes real x, real y, boolexpr filter returns unit
local real r = 800.
loop
call GroupEnumUnitsInRange(udg_GCU_AnyGroup, x, y, r, filter)
exitwhen FirstOfGroup(udg_GCU_AnyGroup) != null
if r >= 3200. then
call GroupEnumUnitsInRect(udg_GCU_AnyGroup, bj_mapInitialPlayableArea, filter)
exitwhen true
endif
set r = 2.00 * r
endloop
set udg_GCU_CurrentPick = null
set udg_GCU_CurrentX = x
set udg_GCU_CurrentY = y
set udg_GCU_CurrentDistance = 100000
call ForGroup(udg_GCU_AnyGroup, function GCU_Enum)
return udg_GCU_CurrentPick
endfunction
//==========================================================================
// Does the same as above. Faster when there are no units that pass the
// filter in a 3200 radius, but at other times slower, and most likely a
// lot slower. How much faster is somewhat directly proportional to the
// amount of units that do not pass the filter inside that 3200 radius.
//
function GetClosestUnitAlt takes real x, real y, boolexpr filter returns unit
set udg_GCU_CurrentPick = null
set udg_GCU_CurrentX = x
set udg_GCU_CurrentY = y
set udg_GCU_CurrentDistance = 100000
call GroupEnumUnitsInRect(udg_GCU_AnyGroup, bj_mapInitialPlayableArea, filter)
call ForGroup(udg_GCU_AnyGroup, function GCU_Enum)
return udg_GCU_CurrentPick
endfunction
//==========================================================================
// Finds the unit that is closest to (x, y) from all units in the specified
// radius, that pass the filter and do not have the locust ability.
//
function GetClosestUnitInRange takes real x, real y, real radius, boolexpr filter returns unit
set udg_GCU_CurrentPick = null
set udg_GCU_CurrentX = x
set udg_GCU_CurrentY = y
set udg_GCU_CurrentDistance = 100000
call GroupEnumUnitsInRange(udg_GCU_AnyGroup, x, y, radius, filter)
call ForGroup(udg_GCU_AnyGroup, function GCU_Enum)
return udg_GCU_CurrentPick
endfunction
//==========================================================================
// Finds the unit that is closest to (x, y) from whichGroup. Unlike the
// other versions this one considers locusted units also.
//
function GetClosestUnitInGroup takes real x, real y, group whichGroup returns unit
set udg_GCU_CurrentPick = null
set udg_GCU_CurrentX = x
set udg_GCU_CurrentY = y
set udg_GCU_CurrentDistance = 100000
call ForGroup(whichGroup, function GCU_Enum)
return udg_GCU_CurrentPick
endfunction
//==========================================================================
// The following three functions do the same as the preceding ones, with //
// the exception that they return groups consisting of the n closest //
// units instead of the closest unit //
//==========================================================================
function GetClosestUnits takes real x, real y, integer n, boolexpr filter returns group
call GroupEnumUnitsInRect(udg_GCU_AnyGroup, bj_mapInitialPlayableArea, filter)
set udg_GCU_ResultingGroup = CreateGroup()
set udg_GCU_CurrentX = x
set udg_GCU_CurrentY = y
loop
exitwhen n == 0
set udg_GCU_CurrentPick = null
set udg_GCU_CurrentDistance = 100000
call ForGroup(udg_GCU_AnyGroup, function GCU_Enum)
exitwhen udg_GCU_CurrentPick == null
call GroupRemoveUnit(udg_GCU_AnyGroup, udg_GCU_CurrentPick)
call GroupAddUnit(udg_GCU_ResultingGroup, udg_GCU_CurrentPick)
set n = n - 1
endloop
return udg_GCU_ResultingGroup
endfunction
function GetClosestUnitsInRange takes real x, real y, real radius, integer n, boolexpr filter returns group
call GroupEnumUnitsInRange(udg_GCU_AnyGroup, x, y, radius, filter)
set udg_GCU_ResultingGroup = CreateGroup()
set udg_GCU_CurrentX = x
set udg_GCU_CurrentY = y
loop
exitwhen n == 0
set udg_GCU_CurrentPick = null
set udg_GCU_CurrentDistance = 100000
call ForGroup(udg_GCU_AnyGroup, function GCU_Enum)
exitwhen udg_GCU_CurrentPick == null
call GroupRemoveUnit(udg_GCU_AnyGroup, udg_GCU_CurrentPick)
call GroupAddUnit(udg_GCU_ResultingGroup, udg_GCU_CurrentPick)
set n = n - 1
endloop
return udg_GCU_ResultingGroup
endfunction
function GCU_AnyGroupAddGroupEnum takes nothing returns nothing
call GroupAddUnit(udg_GCU_AnyGroup, GetEnumUnit())
endfunction
function GetClosestUnitsInGroup takes real x, real y, group whichGroup, integer n returns group
call GroupClear(udg_GCU_AnyGroup)
call ForGroup(whichGroup, function GCU_AnyGroupAddGroupEnum)
set udg_GCU_ResultingGroup = CreateGroup()
set udg_GCU_CurrentX = x
set udg_GCU_CurrentY = y
loop
exitwhen n == 0
set udg_GCU_CurrentPick = null
set udg_GCU_CurrentDistance = 100000
call ForGroup(udg_GCU_AnyGroup, function GCU_Enum)
exitwhen udg_GCU_CurrentPick == null
call GroupRemoveUnit(udg_GCU_AnyGroup, udg_GCU_CurrentPick)
call GroupAddUnit(udg_GCU_ResultingGroup, udg_GCU_CurrentPick)
set n = n - 1
endloop
return udg_GCU_ResultingGroup
endfunction
// End of GetClosestUnit
//==============================================================================
```

Last edited: