Closed zer0ner closed 1 year ago
I came up with a pure 4RPL version of the function for map 1161 (The Aquarium). It is not the fastest function but it works well enough.
# GetUnitsInPolygon(unitType polyList enemyState builtState imperviousState)
:GetUnitsInPolygon
->guip_imperviousState
->guip_builtState
->guip_enemyState
->guip_polyList
->guip_unitType
# Get all units on the map that match the non-position requirements.
GetUnits(<-guip_unitType V3(128 128 128) 512 false false false <-guip_enemyState <-guip_builtState <-guip_imperviousState) ->guip_units
CreateList ->guip_retval
<-guip_units 0 do
<-guip_units[I] ->guip_tempunit
if (@IsPointInPoly(V2(GetUnitCell(<-guip_tempunit)) <-guip_polyList))
AppendToList(<-guip_retval <-guip_tempunit)
endif
loop
<-guip_retval
Example usage (a triangle):
List(
V2(18 148)
V2(138 102)
V2(44 29)
) ->testPoly
@GetUnitsInPolygon("" <-testPoly 2 0 1) ->units
TraceAllSp("Num units " GetListCount(<-units))
<-units 0 do
<-units[I] ->tempunit
CreateEffect("sparks" GetUnitPosition(<-tempunit) V3(1 1 1))
loop
Getting every single unit on a map that matches a set of conditions just to filter them through a set of polygon coordinates works but is kind of expensive and may slow down the frame rate considerably if called too frequently.
In one of my now-scrapped custom maps I kept a list with one entry for every map cell, containing a 0 if no unit had its center there and the unit's ID if one did. Once every second it used GetUnits to get every unit on the map and put it in the correct place if it didn't already exist, and every frame it swept through 1/30 (or as close as I could get) of the list and checked every existing unit it found to make sure it still existed. It let me simulate a blocky raycast against said units (combining their position in the list with the terrain height there) without stepping forward a short distance and re-checking a radius every time.
I don't know if it would serve you well (a possible one-second delay for creation/destruction of units might be too long, or you might not like having to use GetType to manually sort them yourself) but if you've got an obscene number of calls to your existing dot-product polygon intersect checker, you can pare them down to the polygon's bounding square and just check those cells for your broad phase then use the actual method for precise results. Would definitely involve major improvements when checking lots of small polys.
Even without the specific structure I used, an initial bounding-box check (assuming you haven't implemented one already) can save a lot of CPU cycles.
Just some thoughts on what might help until a more formal solution comes about. Happy coding!
Is your feature request related to a problem? Please describe. Not exactly a problem at the moment, just rather inconvenient and inefficient as map makers like me are currently limited to squares and circles as shapes in calls to GetUnits().
Describe the solution you'd like I'd like to be able to pass in a list of X/Z cell position coordinates representing a closed polygon and get back a list of units that match that are located within that polygon.
Describe alternatives you've considered Currently limited to checking a series of smaller squares and circles. However, multiple calls to GetUnits() have to be made (I'm regularly making about 30 GetUnits() calls in a loop in my current map) and, as a result, there can be overlap of the units returned. If an action is taken against all units, units in the overlap regions will have the same actions issued 2-4 times.