• 🏆 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 questions

Status
Not open for further replies.
Level 2
Joined
Dec 21, 2014
Messages
19
Hello all, I am currently learning how to make maps but I got into a problem

How can I instantly end picking other units in the unit group?

For example,
  • Unit Group question
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Set killed = 0
      • Unit Group - Pick every unit in unitGroup and do (Actions)
        • Loop - Actions
          • Unit - Kill (Picked unit)
          • Set killed = (killed + 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • killed Equal to 2
            • Then - Actions
              • -------- Stop picking other units in the unitGroup --------
              • -------- What to put here --------
            • Else - Actions
        • -------- More actions here --------
        • -------- These actions must not be skipped --------
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
use this function:
Does not work. It returns that function call but the loop still keeps calling. Look at the underlying JASS code.

I do not think you can end a unit group loop pre-maturely without crashing the thread. If you can use a destructive loop there is a JASS approach to iterating through unit groups that is both faster and does support pre-mature exiting via an "exitwhen true" statement.

The loop looks like this...
JASS:
local unit u

//...

loop
    set u = FirstOfGroup(udg_unitGroup)
    exitwhen u == null

    //...
    // do stuff here
    //...
    //to exit loop run this.
        set u = null // bug fix
        exitwhen true
    //...

    call GroupRemoveUnit(udg_unitGroup, u)
endloop

// udg_unitGroup may or may not be empty here

Each iteration of the loop removed units from udg_unitGroup permanently. If you want to retain the group contents and use this approach you need to perform a group swap, where units are added to another group in the body of the loop (remember to copy remaining units in case of early exit) and then afterwards the groups are swapped (equivalently re-filling the old group).
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
Is that really faster? If so, can you prove it?
Apparently people have already proved it many times. The reasoning that it is faster is because normal for group loops use a code call which is quite expensive (function calls are expensive, the code might be even more expensive as it behaves differently from normal function calls) where as the destructive loop does not need any non-native function calls to run the body.
 
You can't prematurely end it (without using something similar to a FirstOfGroup loop as DSG said, but that doesn't maintain units in the group), but you can always just make it so that it doesn't do anything for the rest of the units.
  • Unit Group question
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Set killed = 0
      • Unit Group - Pick every unit in unitGroup and do (Actions)
        • Loop - Actions
          • If (killed Equal to 2) then do (Skip remaining actions) else do (Do nothing)
          • Unit - Kill (Picked unit)
          • Set killed = (killed + 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • killed Equal to 2
            • Then - Actions
              • -------- Stop picking other units in the unitGroup --------
              • -------- What to put here --------
            • Else - Actions
      • -------- More actions here --------
      • -------- These actions must not be skipped --------
Something like that. Comparing an integer value for N remaining units is very inexpensive so the performance difference can be ignored.
 
Level 11
Joined
Jan 23, 2015
Messages
788
Make a condition: If Kills is not equal to 2 Then kill picked unit and set the Kills +1
This should bug, the loop will run the actions even though the condition isn't met, to fix that, make a If/Then/Else in the Then action with the same condition and then put kill picked unit and kills = +1 in Then.

Hope you understand me
 
Level 2
Joined
Dec 21, 2014
Messages
19
Thanks for all the reply and I understand Chaosy and RobertMKD mean but I already thought of that one and I'm asking this for alternate solution.
Will PurgeandFire's solution work? Isn't that the same as Skip Remaining Action?
If not, then I guess I have to learn Jass and use FirstOfGroup as DoctorSuperGood suggested.

Oh sorry I finally sew what PurgeandFire mean. It is the same as the other 2 below suggested
 
Level 11
Joined
Jan 23, 2015
Messages
788
  • Events
    • Player - Player 1 (Red) skips a cinematic sequence
  • Conditions
  • Actions
    • Set killed = 0
    • Unit Group - Pick every unit in unitGroup and do (Actions)
      • Loop - Actions
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • killed not equal to 2
        • Then - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • killed not equal to 2
          • Then - Actions
            • Unit - Kill (Picked unit)
            • Set killed = (killed + 1)
          • Else - Actions
          • Else - Actions
That's what I meant
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
Will PurgeandFire's solution work? Isn't that the same as Skip Remaining Action?
His solution would work. It does not stop it picking the units, just makes it so nothing happens when it does past the point that you want to stop picking. There is no way to stop a ForGroup loop once it starts because the entire loop is a function call deferring the body of the loop to a code value (function reference).

"Skip Remaining Actions" will not work because if you look at the underlying JASS code it is simply a "return" statement. This would immediately stop the code value function (as it returns) for that unit, but it will be called again for other units.

This is why in StarCraft II the unit/player group loops were implemented as an iterator function set called in a standard loop structure. That way you can "Skip Remaining Actions" in StarCraft II loops as it returns from the containing function which is usually the elements action block.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
function calls are expensive, the code might be even more expensive as it behaves differently from normal function calls
Function calls are not expensive... ExecuteFunc is but that is a string comparison for every single function in your map.
Functions arent the problem. The problem is a new thread.
Every iteration there is a new thread which is the source of the lagg.

Anyway,
FoG iteration in GUI:
Iteration when creating a group:
  • FoG Iteration 1
    • Events
    • Conditions
    • Actions
      • Set G = (Units in (Playable map area))
      • For each (Integer TempInteger[0]) from 0 to 0, do (Actions)
        • Loop - Actions
          • -------- loop settings --------
          • Custom script: set udg_FoG = FirstOfGroup(udg_G)
          • Custom script: exitwhen udg_FoG == null
          • Unit Group - Remove FoG from G
          • Set TempInteger[0] = -1
          • -------- other actions --------
          • -------- - --------
          • -------- - --------
          • -------- - --------
      • Custom script: call DestroyGroup(udg_G)
Iteration when keeping a group: (I suppose)
  • FoG Iteration 2
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_G = CreateGroup()
      • For each (Integer TempInteger[0]) from 0 to 0, do (Actions)
        • Loop - Actions
          • -------- loop settings --------
          • Custom script: set udg_FoG = FirstOfGroup(udg_G)
          • Custom script: exitwhen udg_FoG == null
          • Unit Group - Remove FoG from MyGroup
          • Unit Group - Add FoG to G
          • Set TempInteger[0] = -1
          • -------- other actions --------
          • -------- - --------
          • -------- - --------
          • -------- - --------
      • Custom script: call DestroyGroup(udg_MyGroup)
      • Set MyGroup = G
 
Status
Not open for further replies.
Top