library GetNearest initializer Init requires GroupUtils //=========================================================================== // Information: //============== // // GetNearest is a very simple library that allows you to find the nearest // unit, destructable, or item to a specified point within a specified radius. // You can use a boolexpr filter as well, just like native Enum functions. All // units/destructables/items outside of the playable map area will be ignored. // //=========================================================================== // GetNearest API: //================= // // GetNearestUnit(x, y, radius, boolexpr) -> unit // This function returns the closest unit to the specified x/y point within // the specified radius matching the specified boolexpr filter. This function // will consider any unit whose collision radius overlaps the specified radius. // // GetNearestDestructable(x, y, radius, boolexpr) -> destructable // This function returns the closest destructable to the specified x/y point // within the specified radius matching the specified boolexpr filter. // // GetNearestItem(x, y, radius, boolexpr) -> item // This function returns the closest item to the specified x/y point within // the specified radius matching the specified boolexpr filter. // //=========================================================================== globals private real MAX_VALUE = 10000000000. //Larger than any squared distance value. private region MapArea private real MaxX private real MinX private real MaxY private real MinY endglobals //=========================================================================== private function GetNearestUnit_Sub takes unit nearest, real x, real y, real radius, boolexpr b returns unit local group g = NewGroup() local real nearestdist = MAX_VALUE local real dist local unit u call GroupEnumUnitsInArea(g, x, y, radius, b) //This function takes collision radius into account. loop //Iterate through the units in the group and find the closest to the specified point. set u = FirstOfGroup(g) exitwhen u == null set dist = Pow(x - GetUnitX(u), 2.) + Pow(y - GetUnitY(u), 2.) if IsUnitInRegion(MapArea, u) and dist < nearestdist then set nearestdist = dist set nearest = u endif call GroupRemoveUnit(g, u) endloop call ReleaseGroup(g) return nearest //Local handle parameters are automatically nulled. endfunction function GetNearestUnit takes real x, real y, real radius, boolexpr b returns unit return GetNearestUnit_Sub(null, x, y, radius, b) endfunction //Avoids leaking a reference to the returned unit. //=========================================================================== globals private rect enumrect = Rect(0., 0., 0., 0.) private real nearestdist = MAX_VALUE private real enumradius = 0. private real enumx = 0. private real enumy = 0. endglobals //! textmacro GetNearestFunc takes NAME, TYPE globals private $TYPE$ nearest$TYPE$ = null endglobals private function GetNearest$NAME$_Enum takes nothing returns nothing local real dist = Pow(enumx - Get$NAME$X(GetEnum$NAME$()), 2.) + Pow(enumy - Get$NAME$Y(GetEnum$NAME$()), 2.) if dist <= enumradius and dist < nearestdist then set nearest$TYPE$ = GetEnum$NAME$() set nearestdist = dist endif endfunction //Enumerate through the dests/items and find the closest one to the point. private function GetNearest$NAME$_Sub takes $TYPE$ nearest, real x, real y, real radius, boolexpr b returns $TYPE$ local real old_enumradius = enumradius //Cache the previous values of the globals. local real old_enumx = enumx local real old_enumy = enumy set enumradius = radius*radius //Assign new values to the globals for this call. set enumx = x set enumy = y call SetRect(enumrect, RMaxBJ(x - radius, MinX), RMaxBJ(y - radius, MinY), RMinBJ(x + radius, MaxX), RMinBJ(y + radius, MaxY)) //Adjust the rect to cover the radius of the enueration. Make sure the rect stays within map boundries. call Enum$NAME$sInRect(enumrect, b, function GetNearest$NAME$_Enum) //Find the closest dest/item to the point. set nearest = nearest$TYPE$ //Assign the closest dest/item to a local variable. set nearest$TYPE$ = null //Restore the previous values for the globals for nested enumerations. set nearestdist = MAX_VALUE set enumradius = old_enumradius set enumx = old_enumx set enumy = old_enumy return nearest //Local handle parameters are automatically nulled. endfunction function GetNearest$NAME$ takes real x, real y, real radius, boolexpr b returns $TYPE$ return GetNearest$NAME$_Sub(null, x, y, radius, b) endfunction //Avoids leaking a reference to the returned dest/item. //! endtextmacro //! runtextmacro GetNearestFunc("Destructable", "destructable") //! runtextmacro GetNearestFunc("Item", "item") //=========================================================================== private function Init takes nothing returns nothing set MapArea = CreateRegion() //Creating a region inside a global block fails, so do it here. set MaxX = GetRectMaxX(bj_mapInitialPlayableArea) //Store the boundries in globals to ensure that dests and items set MinX = GetRectMinX(bj_mapInitialPlayableArea) //are within map boundries. set MaxY = GetRectMaxY(bj_mapInitialPlayableArea) set MinY = GetRectMinY(bj_mapInitialPlayableArea) call RegionAddRect(MapArea, bj_mapInitialPlayableArea) //Add the map rect to a region for IsUnitInRegion(). endfunction endlibrary