Staredit Network > Forums > SC2 Assistance > Topic: [SOLVED] Finding a point from an object
[SOLVED] Finding a point from an object
This topic is locked. You can no longer write replies here.
Apr 8 2012, 10:14 pm
By: Observer12425  

Apr 8 2012, 10:14 pm Observer12425 Post #1



Summary: I need to acquire the X/Y coordinates of a point 3 units away from a unit attacking a Marauder, with the Marauder directly between the unit and the point.

A marauder has concussive shells and wants to kill a zealot. He'll shell it until it gets close, then move a distance away, and then fire again. Wash and repeat until the zealot dies. I'd like to accomplish this using a trigger. I've already found a way to identify when a hostile unit comes within a certain distance of a marauder, but I'm a bit stumped after that. Here's a picture.


I want to have the marauder move directly backward away from the zealot to a point a certain distance away. The problem is actually getting that point.
For the sake of numbers, we'll assume the script activates when the zealot is 2 units away from it and we want the marauder to move back 1 unit, then fire. However, we're not strictly moving it one unit; instead, we'll want it to move to a net of three units from its target's current position. It's fine if it isn't that distance when it stops.

Another related question: can a trigger be run multiple times before the first instance finishes execution? In that case, can multiple instances of the same local variable exist in the separate instances of the trigger?

Let me know if I can clarify anything.

Post has been edited 2 time(s), last time on Apr 8 2012, 10:26 pm by Observer12425.



None.

Apr 9 2012, 2:11 am Roy Post #2

An artist's depiction of an Extended Unit Death

MoveHereAndBlowThatBastardAway
    Events
        Unit - Any Unit Enters within 1.0 of (Position of MY_MARAUDER)
    Local Variables
        AwayPoint = ((Position of MY_MARAUDER) offset by 3.0 towards (Angle from (Position of (Triggering unit)) to (Position of MY_MARAUDER)) degrees) <Point>
    Conditions
        (Unit type of (Triggering unit)) == Zealot
    Actions
        Unit - Order MY_MARAUDER to ( Move targeting AwayPoint) (Replace Existing Orders)
        General - Wait 1.0 Game Time seconds
        Unit - Order MY_MARAUDER to ( Attack targeting (Triggering unit)) (Replace Existing Orders)


Basically, to calculate the away point, you want to get the angle from the Zealot to the Marauder, and then move the Marauder from its current position to the direction of that angle. In the above implementation, I used Point with Polar Offset, with the offset angle being the angle from the Zealot to the Marauder.

Quote from Observer12425
Another related question: can a trigger be run multiple times before the first instance finishes execution? In that case, can multiple instances of the same local variable exist in the separate instances of the trigger?
Short answer: yes and sorta. The local variables are created when the function is called, so they are technically not multiple instances of the same variable. No need for concern here.

Long answer: Local variables should belong to calculations performed when the trigger is fired. Think of it in terms of parameters: if you have a function that adds two numbers, and give it 3 and 5, and then give it another instruction of 2 and 4, the first time it executes it has the parameters 3 and 5, and it can store 8 as a local variable calculated from these values. Simultaneously*, it can store 6 from the second instruction you provided. These two executions can take years to calculate, but they will always remain separate from each other (unless you're also manipulating a global variable, but I don't think you mean to go into a discussion about how threading works).

* Okay, it's not really simultaneous; they can occur concurrently depending on threading, but that is a topic for another time.




Apr 9 2012, 6:53 pm Observer12425 Post #3



Hot damn, that was a quality answer if there ever was one. Thanks, that cleared up a lot.
A slight improvement on top of that I added is immediately issuing the attack order as queued (rather than replacing) so it executes as soon as the marauder reaches the point, not at 1.0 seconds, so the trigger isn't reliant on precise timing.

Result
Required a lot of editing to become 100% efficient.

Mrd. Move and Shoot
    Events
        Unit - Any Unit acquires a target
    Local Variables
        Cooldown = (New timer) <Timer>
        ResultPoint = No Point <Point>
    Conditions
        (Unit type of (Acquired Target)) == Marauder
        Mrd. Script Active == 1
    Actions
        General - While (Conditions) are true, do (Actions)
            Conditions
                ((Triggering unit) Life (Current)) > 0.0
                ((Acquired Target) Life (Current)) > 0.0
            Actions
                General - Wait for (Conditions), checking every 0.1 Game Time seconds
                    Conditions
                        (Distance between (Position of (Triggering unit)) and (Position of (Acquired Target))) <= 2.0
                Variable - Set ResultPoint = ((Position of (Triggering unit)) offset by 6.0 towards ((Position of (Acquired Target)) offset by (0.5, 0.0)))
                Unit - Order (Acquired Target) to ( Move targeting ResultPoint) (Replace Existing Orders)
                Timer - Start Cooldown as a One Shot timer that will expire in 1.4 Game Time seconds
                General - Wait for Cooldown to have 0.0 seconds Remaining
                Unit - Order (Acquired Target) to ( Attack targeting (Triggering unit)) (Replace Existing Orders)
                General - Wait 0.2 Game Time seconds


Post has been edited 10 time(s), last time on Apr 10 2012, 1:09 am by Roy. Reason: Fixed formatting



None.

Apr 10 2012, 3:20 am Roy Post #4

An artist's depiction of an Extended Unit Death

Well, if it works, it works. But I do have a few notes:

Quote from Observer12425
        General - While (Conditions) are true, do (Actions)
            Conditions
                ((Triggering unit) Life (Current)) > 0.0
                ((Acquired Target) Life (Current)) > 0.0
            Actions
                General - Wait for (Conditions), checking every 0.1 Game Time seconds
                    Conditions
                        (Distance between (Position of (Triggering unit)) and (Position of (Acquired Target))) <= 2.0
This has a possibility of entering an infinite loop. It basically says, "If both units are alive, wait until they come close enough to each other." This means it will first check if both units are alive (which will probably be true 100% of the time), and then it will enter a loop waiting for them to come in range of each other, regardless if one or both units die while in this loop. Here's a remedy for that:

General - While (Conditions) are true, do (Actions)
    Conditions
        ((Triggering unit) Life (Current)) > 0.0
        ((Acquired Target) Life (Current)) > 0.0
    Actions
        General - Wait for (Conditions), checking every 0.1 Game Time seconds
            Conditions
                Or
                    Conditions
                        ((Triggering unit) Life (Current)) <= 0.0
                        ((Acquired Target) Life (Current)) <= 0.0
                        (Distance between (Position of (Triggering unit)) and (Position of (Acquired Target))) <= 2.0
        General - If (Conditions) then do (Actions) else do (Actions)
            If
                ((Triggering unit) Life (Current)) > 0.0
                ((Acquired Target) Life (Current)) > 0.0
            Then
                ACTIONS
            Else
                Do Nothing


Also, your ResultPoint seems a bit arbitrary; I'm not sure why you have the (0.5, 0.0) offset there, and you're measuring starting from the Zealot rather than from the Marauder. I'd do something like:

Variable - Set AwayAngle = (Angle from (Position of (Triggering Unit)) to (Position of (Acquired Target)))
Variable - Set AwayDistance = 2.0
Variable - Set ResultPoint = ((Position of (Acquired Target)) offset by AwayDistance towards AwayAngle degrees)
Unit - Order (Acquired Target) to ( Move targeting ResultPoint) (Replace Existing Orders)
Unit - Order (Acquired Target) to ( Attack targeting (Triggering unit)) (After Existing Orders)


Finally, I'm not sure why you're using a timer to wait for 1.4 seconds; why aren't you using your idea of ordering the Marauder to attack after he is done moving (like I implemented above)? It should work fine. Also, you can feel free to use the Wait action in SC2 (there aren't wait block issues like there were in SC1).

So the final trigger would be:

Mrd. Move and Shoot
    Events
        Unit - Any Unit acquires a target
    Local Variables
        ResultPoint = No Point <Point>
        AwayAngle = No Angle <Angle>
        AwayDistance = 0.0 <Real>
    Conditions
        (Unit type of (Acquired Target)) == Marauder
        Mrd. Script Active == 1
    Actions
        General - While (Conditions) are true, do (Actions)
            Conditions
                ((Triggering unit) Life (Current)) > 0.0
                ((Acquired Target) Life (Current)) > 0.0
            Actions
                General - Wait for (Conditions), checking every 0.1 Game Time seconds
                    Conditions
                        Or
                            Conditions
                                ((Triggering unit) Life (Current)) <= 0.0
                                ((Acquired Target) Life (Current)) <= 0.0
                                (Distance between (Position of (Triggering unit)) and (Position of (Acquired Target))) <= 2.0
                General - If (Conditions) then do (Actions) else do (Actions)
                    If
                                (Distance between (Position of (Triggering unit)) and (Position of (Acquired Target))) <= 2.0
                    Then
                        Variable - Set AwayAngle = (Angle from (Position of (Triggering Unit)) to (Position of (Acquired Target)))
                        Variable - Set AwayDistance = 2.0
                        Variable - Set ResultPoint = ((Position of (Acquired Target)) offset by AwayDistance towards AwayAngle degrees)
                        Unit - Order (Acquired Target) to ( Move targeting ResultPoint) (Replace Existing Orders)
                        Unit - Order (Acquired Target) to ( Attack targeting (Triggering unit)) (After Existing Orders)
                    Else
                        Do Nothing

Again, if your trigger works perfectly for your system, there's no need to change it.

(On a side note, if you're having problems formatting your trigger code, try putting it inside [code][/code] tags.)

Edit: And you should change your "Mrd. Script Active" to type Boolean (true/false). Not really important, but as a programmer, it irks me a little.




Options
  Back to forum
Please log in to reply to this topic or to report it.
Members in this topic: None.
[09:31 pm]
RexyRex -- :wob:
[08:28 pm]
NudeRaider -- :wob:
[07:50 pm]
Ultraviolet -- :wob:
[06:09 pm]
UndeadStar -- :wob:
[02:53 pm]
Nekron -- :wob:
[02:13 pm]
lil-Inferno -- :wob:
[06:23 am]
Ultraviolet -- :wob:
[2020-7-01. : 10:26 pm]
O)FaRTy1billion[MM] -- :wob:
[2020-7-01. : 5:11 pm]
MTiger156 -- :wob: athon
[2020-7-01. : 3:06 pm]
NudeRaider -- :wob:amatic
Please log in to shout.


Members Online: Roy, tomarz104, RdeRenato, Dem0n