Unit Coordinate Detection

From Staredit Network Wiki
Revision as of 03:02, 23 November 2012 by DevliN (Talk | contribs) (Location Grid Scanning)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Knowing a unit's coordinates can often be very useful - it can save a lot of locations for RPG's and arena maps.

There are four main ways to detect a unit's coordinates, each with its pros and cons: Constant Updating, Adjusting to Motion, Hybrid Method and scanning with the Location Grid.

All three should be used with Hyper Triggers.

Constant Updating

Constant Updating detects the desired unit's coordinates every trigger cycle without considering whether the unit moved or not. The simplest setup is the following:

Coordexample1.png

The burrowed units are Zerg Zerglings owned by Player 9. The Data Discs are also owned by Player 9. The "XScan" and "YScan" locations must be twice as long as the arena the Marine walks in (including the null borders).

The general idea is that the "XScan" and "YScan" locations are centered on the Marine and the Zerglings they touch are given from Player 9 to Player 10. Then, the "Scan" location scans each line (or axis) of Zerglings and counts how many Player 9 Zerglings are there before the Player 10 Zergling. After all that is done, all the Zerglings are given back to Player 9.

The first trigger, which centers the "XScan" and "YScan" locations, gives the Zerglings and sets the resources (the counters: minerals - X, gas - Y), would be like this:

Trigger("Player 1"){
Conditions:
   Always();
Actions:
   Comment("");
   Preserve Trigger();
   Move Location("Current Player", "Terran Marine", "Anywhere", "XScan");
   Move Location("Current Player", "Terran Marine", "Anywhere", "YScan");
   Give Units to Player("Player 9", "Player 10", "Zerg Zergling", All, "XScan");
   Give Units to Player("Player 9", "Player 10", "Zerg Zergling", All, "YScan");
   Set Resources("Current Player", Set To, 1, ore and gas);

It is followed by a trigger that begins the X coordinate scanning by centering the "Scan" location on the Data Disc:

Trigger("Player 1"){
Conditions:
   Always();
Actions:
   Comment("");
   Preserve Trigger();
   Move Location("All players", "Data Disc", "X Axis", "scan");

After this trigger runs, the situations becomes as seen here:

Coordexample2.png

The first Zergling of the X axis is within that location. The entire scanning and counting process requires that there is only 1 Zergling owned by Player 9 in the "Scan" location at all times.

Then comes the most important part. A set of identical triggers that actually do the counting of Zerglings. This trigger is copied 6 times, as there are 6 coordinates:

Trigger("Player 1"){
Conditions:
   Bring("Player 9", "Men", "scan", At least, 1);
Actions:
   Comment("");
   Preserve Trigger();
   Set Resources("Current Player", Add, 1, ore);
   Move Location("Player 9", "Zerg Zergling", "scan", "scan");
   Give Units to Player("Player 9", "Player 10", "Zerg Zergling", 1, "scan");

If there is a Zergling in the "Scan" location, the Player 10 Zergling has not yet been reached, thus the trigger adds one to the corresponding resource, centers "Scan" on the only Player 9 Zergling that is within it and gives the Zergling it just centered on to Player 10. This process will stop when the 'next' Zergling is owned by Player 10, hence the triggers have reached the Zergling that represents the Marine's X coordinate.

A similar process is then repeated with the Y coordinate.

The Y axis scanning is activated:

Trigger("Player 1"){
Conditions:
   Always();
Actions:
   Comment("");
   Preserve Trigger();
   Move Location("All players", "Data Disc", "Y Axis", "scan");

Then, 6 copies of this triggers are made:

Trigger("Player 1"){
Conditions:
   Bring("Player 9", "Men", "scan", At least, 1);
Actions:
   Comment("");
   Preserve Trigger();
   Set Resources("Current Player", Add, 1, gas);
   Move Location("Player 9", "Zerg Zergling", "scan", "scan");
   Give Units to Player("Player 9", "Player 10", "Zerg Zergling", 1, "scan");

By now the coordinates have been fully calculated and transferred into minerals and gas. The only thing left to do is to give the Zerglings back from Player 10 to Player 9:

Trigger("Player 1"){
Conditions:
   Always();
Actions:
   Comment("");
   Preserve Trigger();
   Give Units to Player("Player 10", "Player 9", "Zerg Zergling", All, "Anywhere");

Pros and Cons

The pros of this system is that is constantly updates, no matter what happens to the unit in question. Even if it is moved (teleported) to a place the coordinates of which are not possible to compute (for example teleported to a nearby enemy unit, with many other enemy units of the same type around).

The main problem of this system is lag. It scans through the coordinate units once per trigger cycle; if the area in which your unit can walk in gets big, there will be a lot of giving going on, hence a lot of lag. This can be countered by splitting each axis into segments and use only one sengment for coordinate detection; once the unit moves onto another segment, turn the onld one off and turn the new one on.

Another problem that appears when the area of detection becomes bigger is the amount of units. Make sure the system does not eat up too many units by reducing accuracy if possible.

Adjustment to Motion

This method detects change in the unit's coordinates. When the unit has moved enough to change his coordinate, the map detects what coordinates have changed and how: increased or decreased.

As seen in the map Unit Coordinates, each axis is made of repeating set of three things - two mines owned by different players and one empty spot:

Coordexample3.png

The order of these things is: 'nothing', Player 8 Spider Mine, Player 7 Spider Mine. Let us call them 'N', 'P8' and 'P7' respectively. It is clear that if the location that is centered on the unit used to detect the X/Y coordinate moves from P8 to N, the unit moved left/up, hence the X/Y coordinate is decreased; if the location moves from P7 to N, the unit moved right/down, and so on. There are 6 possible conditions:

Coordinate increase:

  1. From N to P8
  2. From P8 to P7
  3. From P7 to N

Coordinate decrease:

  1. From P7 to P8
  2. From P8 to N
  3. From N to P8

Pros and Cons

An obvious advantage of this system is that it doesn't lag at all, since moving locations and modifying switches or deathcounters are lag-free operations.

Another advantage is the possibility to use 1/3 less units than the Constant Updating system. When dealing with large maps, especially RPGs and RPs, this might become crucial.

The only disadvantage is the inability to restore the unit's cordinates if they are lost or miscalculated. An obvious example of such a case might be the unit getting teleported to one of several nearby enemies of the same type. Of course, if your map has something that might break this system, either isolate it or use different system. One possible workaround is to use three units instead of two units and an empty space. In case the coordinates are lost, it can be converted into the Constant Updating system to get the coordinates, and then switched back to its normal state.

Hybrid Coordinate System

The Hybrid Coordinate System combines the strengths of of Constant Updating and Adjustment to Motion - it is both lagless and reliable in all situations. It uses pre-placed units that are different in some way, just like Adjustment to Motion. Scanning through the axis units is made without any "Give Unit" commands, which makes it lagless. A simple setup might look like this:

Hybridexample.png

All units in the axis (owned by Player 9) are set in the following pattern: Khalis Crystal (KC), Psi Emitter (PE), Young Chrysalis (YC), KC, PE, YC ...

The first trigger is quite similar to that of Constant Updating. It gives the units corresponding to the Marine's coordinates from Player 9 to Player 10:

Trigger("Player 1"){
Conditions:
   Always();
Actions:
   Comment("");
   Preserve Trigger();
   Move Location("Current Player", "Terran Marine", "Anywhere", "XScan");
   Move Location("Current Player", "Terran Marine", "Anywhere", "YScan");
   Give Units to Player("Player 9", "Player 10", "Any unit", All, "XScan");
   Give Units to Player("Player 9", "Player 10", "Any unit", All, "YScan");
   Set Resources("Current Player", Set To, 1, ore and gas);

Then, the following trigger initiates the scanning of the X axis:

Trigger("Player 1"){
Conditions:
   Always();
Actions:
   Comment("");
   Preserve Trigger();
   Move Location("All players", "Khalis Crystal", "X Axis", "scan");
   Move Location("All players", "Khalis Crystal", "X Axis", "c.p.");

"c.p." stands for 'current position' - it is an additional location required for scanning.

The scanning of the X axis consists of copied sets of three triggers (a trigger per unit type on the axis):

Trigger("Player 1"){
Conditions:
   Bring("Player 9", "Khalis Crystal", "c.p.", At least, 1);
Actions:
   Comment("");
   Preserve Trigger();
   Set Resources("Current Player", Add, 1, ore);
   Move Location("All players", "Psi Emitter", "scan", "c.p.");
   Move Location("All players", "Psi Emitter", "scan", "scan");
Trigger("Player 1"){
Conditions:
   Bring("Player 9", "Psi Emitter", "c.p.", At least, 1);
Actions:
   Comment("");
   Preserve Trigger();
   Set Resources("Current Player", Add, 1, ore);
   Move Location("All players", "Young Chrysalis", "scan", "c.p.");
   Move Location("All players", "Young Chrysalis", "scan", "scan");
Trigger("Player 1"){
Conditions:
   Bring("Player 9", "Young Chrysalis", "c.p.", At least, 1);
Actions:
   Comment("");
   Preserve Trigger();
   Set Resources("Current Player", Add, 1, ore);
   Move Location("All players", "Khalis Crystal", "scan", "c.p.");
   Move Location("All players", "Khalis Crystal", "scan", "scan");

This set of three triggers considers what unit the "c.p." location is centered on. If it is a KC, it centers both "c.p." and "scan" on PE, etc. Thus the two locations move by the following rule:

  • KC -> PE
  • PE -> YC
  • YC -> KC

Which is exactly the order of the axis units. Hence the locations "c.p." and "scan" will go through all the axis units until the "c.p." location gets centered on a Player 10 unit.

For this particular example, there must be two sets of triggers described above, placed one after another, since there are 6 coordinate units on each axis. Note that units of the same type owned by different players can be used as well.

After the X axis has been scanned, the Y axis scan is initiated in a similar way:

Trigger("Player 1"){
Conditions:
   Always();
Actions:
   Comment("");
   Preserve Trigger();
   Move Location("All players", "Khalis Crystal", "Y Axis", "scan");
   Move Location("All players", "Khalis Crystal", "Y Axis", "c.p.");

And a similar trigger set is copied to fit the amount of coordinate units in that axis:

Trigger("Player 1"){
Conditions:
   Bring("Player 9", "Khalis Crystal", "c.p.", At least, 1);
Actions:
   Comment("");
   Preserve Trigger();
   Set Resources("Current Player", Add, 1, gas);
   Move Location("All players", "Psi Emitter", "scan", "c.p.");
   Move Location("All players", "Psi Emitter", "scan", "scan");
Trigger("Player 1"){
Conditions:
   Bring("Player 9", "Psi Emitter", "c.p.", At least, 1);
Actions:
   Comment("");
   Preserve Trigger();
   Set Resources("Current Player", Add, 1, gas);
   Move Location("All players", "Young Chrysalis", "scan", "c.p.");
   Move Location("All players", "Young Chrysalis", "scan", "scan");
Trigger("Player 1"){
Conditions:
   Bring("Player 9", "Young Chrysalis", "c.p.", At least, 1);
Actions:
   Comment("");
   Preserve Trigger();
   Set Resources("Current Player", Add, 1, gas);
   Move Location("All players", "Khalis Crystal", "scan", "c.p.");
   Move Location("All players", "Khalis Crystal", "scan", "scan");

After both axis have been scanned, a trigger must give the units owned by Player 10 back to Player 9 in the both axis locations:

Trigger("Player 1"){
Conditions:
   Always();
Actions:
   Comment("");
   Preserve Trigger();
   Give Units to Player("Player 10", "Player 9", "Any unit", All, "X Axis");
   Give Units to Player("Player 10", "Player 9", "Any unit", All, "Y Axis");

Pros and Cons

There are no serious disadvantages to this system. The only possible problem is the amount of units it requires.

Location Grid Scanning

If a map already uses a Location Grid, there might be a point not to add any units and use it to detect the location of a unit. Use the longest coordinate location in the dynamic axis and center it on all the coordinate locations of the static axis until the desired unit is found. Center a 'middleman' location on the static coordinate location, and then start centering the mobile axis' coordinate locations, with each one 'shorter' than the previous one. Do thins until the unit disappears from the location - this will mean that a location that is not long enough to reach the unit has been found; hence the approximate coordinate of the unit can be calculated by multiplying the value of the first location that is not long enough by two. After the approximate coordinates are known, all that remains is to check two grid points. This method needs less location checking, but requires some binary countoff operations (multiplying). Alternatively, one could always just scan through every grid point of the first found coordinate.