HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Circular regions

08-08-2011, 08:44 PM#1
Fallen-God[LcR]
Hey,

Basically what I am trying to do is detect when a unit leaves a COP, re-writing someone else's GUI triggers into vJass. I am a programmer, but this task is my first experience with Warcraft III triggering.

At the moment, rectangular regions are created at every COP, but obviously a rectangle is a poor approximation to a circle.
Having read another topic, I gather that a region is a collection on "cells", which I presume are squares, but I have no idea how big a cell is, and whether it is possible to create a collection of cells to be a better approximation to a circle.

I see there is a RegionAddCell method which could presumably be used to create a better approximation, but if I am going to get this done I may as well ask here and get it done properly, rather than trying my own way and creating some kind of botch job.
All of the regions are created and bound to event handlers when the map initializes, so it is not overly important if it takes a long time to create each region as it will only happen once, at the start.

Unfortunately my knowledge in what is possible in WE is woefully lacking.


Cheers
08-08-2011, 10:41 PM#2
Anitarf
I personally prefer periodically enumerating units in range/rect to using triggers with unit-enters-region events, but if you're already stuck with doing it that way that's not a problem.

For an approximation of a circle, I would suggest using RegionAddRect to add multiple overlapping rects to your region, each constructed in such a way that the circle we are approximating is its circumscribed circle. Something like this:
Collapse JASS:
    local rect r
    local region rg=CreateRegion()
    local real radius=1024.0 // the radius of the circle we are approximating
    local real angle=(bj_PI/2)-(bj_PI/20) // 90 degrees minus half our step
    loop
        exitwhen angle<0.0
        set r=Rect(-Cos(angle)*radius, -Sin(angle)*radius, Cos(angle)*radius, Sin(angle)*radius)
        call RegionAddRect(rg,r)
        call RemoveRect(r)
        set angle=angle-bj_PI/10 // 5 steps per quarter circle
    endloop
    set r=null
08-08-2011, 10:48 PM#3
BBQ
RegionAddCell() adds the 32x32 cell in which the specified coordinates belong (you can see the cells when you open the WE - the smallest ones (marked with grey lines) are 32x32, the medium-sized ones (marked with white lines) are 128x128, while the biggest ones (marked with yellow lines) are 512x512).

Just answering what Anitarf didn't...
08-08-2011, 10:59 PM#4
Fallen-God[LcR]
Quote:
Originally Posted by Anitarf
I personally prefer periodically enumerating units in range/rect to using triggers with unit-enters-region events, but if you're already stuck with doing it that way that's not a problem.

For an approximation of a circle, I would suggest using RegionAddRect to add multiple overlapping rects to your region, each constructed in such a way that the circle we are approximating is its circumscribed circle. Something like this:
Collapse JASS:
    local rect r
    local region rg=CreateRegion()
    local real radius=1024.0 // the radius of the circle we are approximating
    local real angle=(bj_PI/2)-(bj_PI/20) // 90 degrees minus half our step
    loop
        exitwhen angle<0.0
        set r=Rect(-Cos(angle)*radius, -Sin(angle)*radius, Cos(angle)*radius, Sin(angle)*radius)
        call RegionAddRect(rg,r)
        call RemoveRect(r)
        set angle=angle-bj_PI/10 // 5 steps per quarter circle
    endloop
    set r=null
Well there are 150-odd of these regions, and the event handler needs to be called as soon as the unit leaves, even a modest delay would look terrible. I don't particularly fancy looping through 150 regions every 1/10th of a second.

Thanks very much for the code.

One question, do rects map flawlessly to regions, or are regions confined to a collection of XxX (X by X) squares?
I don't know if I have explained what I mean well, ask if you don't understand.
08-08-2011, 11:01 PM#5
Fallen-God[LcR]
Quote:
Originally Posted by BBQ
RegionAddCell() adds the 32x32 cell in which the specified coordinates belong (you can see the cells when you open the WE - the smallest ones (marked with grey lines) are 32x32, the medium-sized ones (marked with white lines) are 128x128, while the biggest ones (marked with yellow lines) are 512x512).

Just answering what Anitarf didn't...
Ah, thank you very much. It took me embarrassingly long to find out how to even add the grid lines in, but you get much better resolution than I expected.
08-09-2011, 10:05 AM#6
Anitarf
Quote:
Originally Posted by Fallen-God[LcR]
Well there are 150-odd of these regions, and the event handler needs to be called as soon as the unit leaves, even a modest delay would look terrible. I don't particularly fancy looping through 150 regions every 1/10th of a second.
The thing is, WC3 itself has a delay, since it apparently does region events by periodically checking the units too. A simple test shows that enter region events occur only every 0.03 seconds:
Expand JASS:
Periodical group enumerations are actually more efficient in many cases. The only way to really be sure which is faster in this case would of course be to write both implementations and then stress-test them under identical conditions that best resemble the conditions during gameplay. If the region approach already performs adequately then I can understand why you wouldn't want to waste your time on this, but don't dismiss the periodic check approach just because you'd need to loop through 150 range group enums every 0.1 seconds - the trigger approach also does some form of looping every 0.03 seconds and grows less efficient the more often units enter regions due to the high cost of starting a trigger in WC3, whereas the group enum approach only needs to start a constant number of new threads every second while the group operations that scale up with the number of units are reasonably fast.