• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Unit Group Detection Problem

Status
Not open for further replies.
Level 7
Joined
May 30, 2018
Messages
290
Hello Hive,

for an arena styled map I made these simple triggers (for the waves and the time in between them):

  • Set up Arena
    • Events
      • Time - ArenaTimer expires
    • Conditions
    • Actions
      • Set VariableSet ArenaLocation[1] = (Center of Region 000 <gen>)
      • Set VariableSet ArenaLocation[2] = (Center of Region 001 <gen>)
      • Set VariableSet ArenaLocation[3] = (Center of Region 002 <gen>)
      • For each (Integer A) from 1 to 10, do (Actions)
        • Loop - Actions
          • Unit Group - Pick every unit in PlayerUnitGroup and do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Owner of (Picked unit)) Equal to (Player((Integer A)))
                • Then - Actions
                  • Unit - Move (Picked unit) instantly to ArenaLocation[(Integer A)]
                  • Custom script: call RemoveLocation(udg_ArenaLocation[GetForLoopIndexA()])
                • Else - Actions
  • Arena Fight
    • Events
      • Time - ArenaTimer expires
    • Conditions
    • Actions
      • Countdown Timer - Destroy Arena_Window
      • Set VariableSet Wave = (Wave + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Wave Equal to 1
        • Then - Actions
          • Set VariableSet ArenaLocation[1] = (Center of Region 000 <gen>)
          • Set VariableSet ArenaLocation[2] = (Center of Region 001 <gen>)
          • Set VariableSet ArenaLocation[3] = (Center of Region 002 <gen>)
          • For each (Integer A) from 1 to 10, do (Actions)
            • Loop - Actions
              • Unit - Create 1 Footman for Player 12 (Brown) at ArenaLocation[(Integer A)] facing Default building facing degrees
              • Unit Group - Add (Last created unit) to ArenaMobs
        • Else - Actions
          • Countdown Timer - Start ArenaTimer as a One-shot timer that will expire in 10.00 seconds
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Wave Equal to 2
        • Then - Actions
          • Set VariableSet ArenaLocation[1] = (Center of Region 000 <gen>)
          • Set VariableSet ArenaLocation[2] = (Center of Region 001 <gen>)
          • Set VariableSet ArenaLocation[3] = (Center of Region 002 <gen>)
          • For each (Integer A) from 1 to 10, do (Actions)
            • Loop - Actions
              • Unit - Create 2 Footman for Player 12 (Brown) at ArenaLocation[(Integer A)] facing Default building facing degrees
              • Unit Group - Add (Last created unit) to ArenaMobs
        • Else - Actions
  • Wave finish
    • Events
      • Unit - A unit owned by Player 12 (Brown) Dies
    • Conditions
    • Actions
      • Set VariableSet ArenaMobs_Count = ((Number of units in ArenaMobs) - 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ArenaMobs_Count Equal to 0
        • Then - Actions
          • Countdown Timer - Start ArenaTimer as a One-shot timer that will expire in 10.00 seconds
          • Countdown Timer - Create a timer window for ArenaTimer with title Arena Start
          • Set VariableSet Arena_Window = (Last created timer window)
          • Set VariableSet ShopLocation[1] = (Center of Region 003 <gen>)
          • Set VariableSet ShopLocation[2] = (Center of Region 004 <gen>)
          • Set VariableSet ShopLocation[3] = (Center of Region 005 <gen>)
          • For each (Integer A) from 1 to 10, do (Actions)
            • Loop - Actions
              • Unit Group - Pick every unit in PlayerUnitGroup and do (Actions)
                • Loop - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Owner of (Picked unit)) Equal to (Player((Integer A)))
                    • Then - Actions
                      • Unit - Move (Picked unit) instantly to ShopLocation[(Integer A)]
                      • Custom script: call RemoveLocation(udg_ShopLocation[GetForLoopIndexA()])
                    • Else - Actions
        • Else - Actions
Up until the last trigger everything is working. I just think there is a problem with the detection/count of units in the group "ArenaMobs", because after all units of player 12 in the first wave die, nothing happens. The last trigger does not get initiated so to speak.

Another question regarding Unit Groups in general: Why is it with the following trigger that always only one of the three spawned units gets teleported with the "Set Up Arena" trigger, what would I need to change, that every unit gets telported instead?
  • Test
    • Events
      • Time - Elapsed game time is 2.00 seconds
    • Conditions
    • Actions
      • Unit - Create 3 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
      • Unit Group - Add (Last created unit) to PlayerUnitGroup
      • Unit - Create 3 Footman for Player 2 (Blue) at (Center of (Playable map area)) facing Default building facing degrees
      • Unit Group - Add (Last created unit) to PlayerUnitGroup
      • Unit - Create 3 Footman for Player 3 (Teal) at (Center of (Playable map area)) facing Default building facing degrees
      • Unit Group - Add (Last created unit) to PlayerUnitGroup
Thanks in advance.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,546
So the first thing I would do is Set ArenaLocation and ShopLocation during Map Initialization. It looks to me like these Points are meant to exist throughout the game so treating them like "temporary" variables which you constantly Set/Remove is unnecessary. Just Set them once and let them be.

Next, understand that dead units aren't removed from Unit Groups. So when you do this:
  • Set Variable ArenaMobs_Count = ((Number of units in ArenaMobs) - 1)
You're never going to reach 0 because you're counting the dead units as well, unless of course there was only 1 unit in ArenaMobs to begin with.

Instead, do this:
  • Unit Group - Remove (Triggering unit) from ArenaMobs
  • Set Variable ArenaMobs_Count = (Number of units in ArenaMobs)

Regarding Last created unit, understand that Last created unit is just a global Unit variable, it has no special properties beyond what a standard Unit variable can do. This means it can only be set to one unit at a time. Also, understand that 3 Footman aren't actually created at the same time with that Action, here's what's really happening behind the scenes:

A For Loop runs 3 times, creating 1 Footman each cycle:
Cycle 1: Create 1 Footman
Cycle 2: Create 1 Footman
Cycle 3: Create 1 Footman <--- Last created unit

This is why it only adds 1 of the Footman. Luckily the solution is simple, use the Add Unit Group function:
  • Unit Group - Add all units of (Last created unit group) to PlayerUnitGroup
The Create Units function also adds those 3 Footman to a unit group that you can take advantage of here.

I'd also advise against using IntegerA in your For Loops and instead use a unique Integer variable for each one. This is to avoid overwriting the value of IntegerA, which can happen if you have multiple Loops running at the same time that all use IntegerA. It's not always an issue because it really depends on the Triggers/Events/Actions used. In your case I would at the very least create a new integer variable to replace IntegerA in the Wave finish trigger. This is because it runs whenever a unit dies which is an easy Event to fire from other triggers.

And what's the deal with your For Loops running from 1 to 10? It looks like you only have 3 ArenaLocations and ShopLocations. Also, careful with using Loops for everything, sometimes a Pick Every Player/Unit function is better. For example in your Wave finish trigger you could simplify it to this:
  • Unit Group - Pick every unit in PlayerUnitGroup and do (Actions)
    • Loop - Actions
      • Set Variable PN = Player number of (Owned of Picked unit)
      • Unit - Move (Picked unit) instantly to ShopLocation[PN]
^ With this design you don't have to pick every single unit 10 different times. This is A LOT more efficient. Just be careful with using PN in too many places, you don't want to accidentally overwrite it's value. It can suffer from the same issue as IntegerA if you aren't careful.

Matter of fact, it's pretty much useless in the above example since you only take advantage of it once. Instead you could just do:
  • Unit - Move (Picked unit) instantly to ShopLocation[Player number of (Owned of Picked unit)]

Lastly, you're leaking 3 Points in that Test trigger, but you're probably already aware of this.
 
Last edited:
Level 7
Joined
May 30, 2018
Messages
290
So the first thing I would do is Set ArenaLocation and ShopLocation during Map Initialization. It looks to me like these Points are meant to exist throughout the game so treating them like "temporary" variables which you constantly Set/Remove is unnecessary. Just Set them once and let them be.

Next, understand that dead units aren't removed from Unit Groups. So when you do this:
  • Set Variable ArenaMobs_Count = ((Number of units in ArenaMobs) - 1)
You're never going to reach 0 because you're counting the dead units as well, unless of course there was only 1 unit in ArenaMobs to begin with.

Instead, do this:
  • Unit Group - Remove (Triggering unit) from ArenaMobs
  • Set Variable ArenaMobs_Count = (Number of units in ArenaMobs)

Regarding Last created unit, understand that Last created unit is just a global Unit variable, it has no special properties beyond what a standard Unit variable can do. This means it can only be set to one unit at a time. Also, understand that 3 Footman aren't actually created at the same time with that Action, here's what's really happening behind the scenes:

A For Loop runs 3 times, creating 1 Footman each cycle:
Cycle 1: Create 1 Footman
Cycle 2: Create 1 Footman
Cycle 3: Create 1 Footman <--- Last created unit

This is why it only adds 1 of the Footman. Luckily the solution is simple, use the Add Unit Group function:
  • Unit Group - Add all units of (Last created unit group) to PlayerUnitGroup
Blizzard adds those 3 Footman to a unit group that you can take advantage of here.

I'd also advise against using IntegerA in your For Loops and instead use a unique Integer variable for each one. This is to avoid overwriting the value of IntegerA, which can happen if you have multiple Loops running at the same time that all use IntegerA. It's not always an issue because it really depends on the Triggers/Events/Actions used. In your case I would at the very least create a new integer variable to replace IntegerA in the Wave finish trigger. This is because it runs whenever a unit dies which is an easy Event to fire from other triggers.

And what's the deal with your For Loops running from 1 to 10? It looks like you only have 3 ArenaLocations and ShopLocations. Also, careful with using Loops for everything, sometimes a Pick Every Player/Unit function is better. For example in your Wave finish trigger you could simplify it to this:
  • Unit Group - Pick every unit in PlayerUnitGroup and do (Actions)
    • Loop - Actions
      • Set Variable PN = Player number of (Owned of Picked unit)
      • Unit - Move (Picked unit) instantly to ShopLocation[PN]
^ With this design you don't have to pick every single unit 10 different times. This is A LOT more efficient. Just be careful with using PN in too many places, you don't want to accidentally overwrite it's value. It can suffer from the same issue as IntegerA if you aren't careful.

Matter of fact, it's pretty much useless in the above example since you only take advantage of it once. Instead you could just do:
  • Unit - Move (Picked unit) instantly to ShopLocation[Player number of (Owned of Picked unit)]


Lastly, you're leaking 3 Points in that Test trigger, but you're probably already aware of this.
Thanks for stepping in again Uncle! Your remarks make very much sense, I definitely can work off of them :D! And yeah, I know about the leaks, most of the time I fix them after making the trigger itself work :)
 
Status
Not open for further replies.
Top