HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Find Region That Was Entered?

01-17-2008, 11:47 PM#1
Brash
I have 650 identical regions spread out evenly. I've looked and looked and havn't been able to figure out a full-proof way to track which region was entered.

The best i could come up with was this:

at gamestart i:

Trigger:
DestructiblesNonLocal
Collapse Events
Time - Elapsed game time is 1.00 seconds
Conditions
Collapse Actions
Collapse For each (Integer A) from 1 to 650, do (Actions)
Collapse Loop - Actions
Trigger - Add to Enter Step <gen> the event (Unit - A unit enters FootSwitch_Region[integer a])

Then i have the "Enter Step" trigger with events now because the previous trigger created them.

so now when any of those regions is entered, it will go off.. but how do i find out which region it was?

The best thing i could come up with was setting the position of the Entering Unit and then running a loop for 1 - 650 times with an "if/than/else" checking if "region [Integer a]" contained that point... and it works most of the time. but sometimes it doesn't catch.. for some reasion. my guess is that loop-checking 650 times is way too much when i have several units on the map that may - at any given time - step into any one of these regions... so i think the game sometimes skips and misses catching when a unit enters.

is there a better way to identify what region was entered? i need something solid to handle the possibility of many units walking into many different regions at any given time.
01-18-2008, 12:22 AM#2
EnderA
This is a bug in Warcraft, sometimes the "enter's a region" will fire, yet when checking if the unit is inside the region it will return false.

See the bug explanation here.
01-18-2008, 01:06 AM#3
rain9441
Ah the classic what region did I enter problem...

Heres my solution:

Have 1 trigger per region.
650 Regions
650 Triggers

Then you have 2 options:


Option A:

2 Global Arrays, one array with the regions, one array with the triggers. When a trigger fires, you loop through all 650 triggers, when TriggerArray[index] == GetTriggeringTrigger(), you have entered RegionArray[index].

Option B:

Have one Global array of regions. Use Gamecache as a handle->integer hash. Store I2S(H2I(trigger)) into gamecache with the value of the index which contains the appropriate region. Then in the trigger fetch I2S(H2I(GetTriggeringTrigger())) from gamecache, use the returned value as the index to RegionArray.

Option A is O(n) where n = number of regions. Not terribly bad, its not exponential, linear is managable. Option B is O(1), but uses H2I and gamecache.


IF your making a pathing system theres option C, but it doesnt look like you are. Option C consists of keeping track of where a unit is heading by storing the actual trigger associated with the region it is heading to on the unit, this way you can check if the unit's destined trigger is GetTriggeringTrigger(), and you then know that it entered its destined region and go from there. But like I said it doesnt appear to be the case that you are doing this.

Personally I'd go with Option B. Good luck!
01-18-2008, 06:42 AM#4
Brash
hm, i'm kinda weak on both options...
in Option A are you saying to create 650 triggers in the editor or use a trig to creat 650 mid-game?

If you mean mid-game, how is that done? Never did that before.

and for option B i've hardly ever used gamecache due to many people saying that it is apt to cause lag.
so option A sounds more feasable..if i can figure out what you mean by how to handle 650 triggers... i don't want to write out litteraly that many manually...

its too bad there isn't a simple "getenteredregion()"
01-18-2008, 08:41 AM#5
Troll-Brain
with gui a region is in reality a rect.
when you use a region event, it creates a new region and add the rect to it ( a region can have some rect ans cells).
There is this function :
Collapse JASS:
GetTriggeringRegion()
but not
Collapse JASS:
GetTriggeringRect()

There is an other way, if your regions are enough smalls and far for each other, you can calculate the 650 distances beetween the position of your unit and the center of the regions, and then take the smallest value

I've make it for someome else there are the triggers :

Trigger:
MAP
Collapse Evenements
Map initialization
Conditions
Collapse Actions
Set Reg[1] = Point1 <gen>
Set Reg[2] = Point2 <gen>
Set Reg[3] = Point3 <gen>
Set Reg[4] = Point4 <gen>
Collapse For each (Integer A) from 1 to 4, do (Actions)
Collapse Boucle - Actions
Set Center[(Integer A)] = (Center of Reg[(IntegerA)])
Set Unit[1] = Fantassin 0000 <gen>
Set ResuPoint[1] = (Center of Depart <gen>)

Trigger:
Point
Collapse Evenements
Unit - A unit enters Point1 <gen>
Unit - A unit enters Point2 <gen>
Unit - A unit enters Point3 <gen>
Unit - A unit enters Point4 <gen>
Collapse Conditions

Collapse Actions
Set Dist = 1000000000.00
Set U = (Triggering unit)
Set TempPoint = (Position of U)
Collapse For each (Integer A) from 1 to 4, do (Actions)
Collapse Boucle - Actions
Set R = (Distance between Center[(Integer A)] and TempPoint)
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse Si - Conditions
R < Dist
Collapse Alors - Actions
Set Index = (Integer A)
Set Dist = R
Sinon - Actions
Set ResuPoint[(Player number of (Owner of U))] = Center[(Index)]
Special effect - Create a special effect at (Center of Reg[Index]) using Abilities\Spells\Other\HowlOfTerror\HowlCaster.mdl
Special effet - Destroy (Last created special effect)
Son - Play Rescue <gen>
Custom script: call RemoveLocation(udg_TempPoint)
01-18-2008, 01:39 PM#6
rain9441
Region Trigger

Trigger:
Actions
Collapse For each (Integer index) from 1 to 650, do (Actions)
Collapse Loop - Actions
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
TriggerArray[index] Equal to (This trigger)
Collapse Then - Actions
-------- Your Code Here, RegionArray[index] == EnteredRegion --------
Else - Actions

Setup Trigger

Trigger:
Actions
-------- Make sure this stuff runs after you setup your RegionArray --------
Collapse For each (Integer index) from 1 to 650, do (Actions)
Collapse Loop - Actions
Custom script: set udg_TriggerArray[udg_index] = CreateTrigger()
Trigger - Add to TriggerArray[index] the event (Unit - A unit enters RegionArray[index])
Custom script: call TriggerAddAction(udg_TriggerArray[udg_index], function Trig_Region_Trigger_Actions)
01-18-2008, 03:52 PM#7
Brash
Trigger:
TriggerArray[index] Equal to (This trigger)
what is the purpose of it checking if it is equal to this trigger?
01-18-2008, 03:59 PM#8
Troll-Brain
You got the index of the trigger and so the index of the region
07-28-2008, 12:36 PM#9
ToukoAozaki
I'd suggest using regions instead of rects. GetTriggeringRegion(), as posted above, is a perfect way of doing it. With using some systems to put some data (e.g. array indices) on the handles, that would remove any need to use such a large loop.

Collapse JASS:
// region APIs
native CreateRegion             takes nothing returns region
native RemoveRegion             takes region whichRegion returns nothing

native RegionAddRect            takes region whichRegion, rect r returns nothing
native RegionClearRect          takes region whichRegion, rect r returns nothing

native RegionAddCell           takes region whichRegion, real x, real y returns nothing
native RegionAddCellAtLoc      takes region whichRegion, location whichLocation returns nothing
native RegionClearCell         takes region whichRegion, real x, real y returns nothing
native RegionClearCellAtLoc    takes region whichRegion, location whichLocation returns nothing

native IsUnitInRegion               takes region whichRegion, unit whichUnit returns boolean
native IsPointInRegion              takes region whichRegion, real x, real y returns boolean
native IsLocationInRegion           takes region whichRegion, location whichLocation returns boolean

// for event registration
native TriggerRegisterEnterRegion takes trigger whichTrigger, region whichRegion, boolexpr filter returns event

BTW, doesn't that loop executing 650 times hit op limit? That seems to be too large. I had a loop which was supposed to run 150x150=22500 times (to replace the entire terrain) and it only ran about 500~600 times.

Edit: My estimation was wrong. Though that won't hit op limit, I still recommend using regions.
07-28-2008, 03:14 PM#10
Themerion
Without using JASS/Custom Scripts, you won't get a good solution. What you can do, is to check slightly larger regions/rects.

This is how your Enter Step-trigger would look like. The custom script-parts are for preventing leaks.

Trigger:
Enter Step
Events
Conditions
Collapse Actions
Set TempInt = -1
Collapse For each (Integer A) from 1 to 650, do (Actions)
Collapse Loop - Actions
Set TempLoc = (Center of FootSwitch_Region[(Integer A)])
Set TempRect = (Region centered at TempLoc with size (((Width of FootSwitch_Region[(Integer A)]) + 16.00), ((Height of FootSwitch_Region[(Integer A)]) + 16.00)))
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
(TempRect contains (Entering unit)) Equal to True
Collapse Then - Actions
Set TempInt = (Integer A)
Custom script: call RemoveLocation(udg_TempLoc)
Custom script: call RemoveRect(udg_TempRect)
Custom script: exitwhen true
Else - Actions
Custom script: call RemoveLocation(udg_TempLoc)
Custom script: call RemoveRect(udg_TempRect)

Footnote:
Custom Script: exitwhen true
This is how you tell Warcraft to immediately interrupt a loop.
07-28-2008, 04:16 PM#11
Troll-Brain
Btw, the last post was written by me on 01-18-2008, 05:59 PM
Necromancy ?