[General] Make Units Spawn as Groups

So, if anyone has ever played the Lord of the Rings RTS game, I am trying to make my units like theirs (1 unit visually appears as many small units)

I am hoping this has already been done because its absolutely melting my brain trying to get this working.

Essentially, I want:

  • when unit is trained or spawned - trigger places many dummy units in area around it
  • these dummy units mimic the orders of their parent. moving along side them (in relation to their offset from the main unit)
  • These dummy units will play attack animations when the main unit attacks (ideally with randomized wait times between attacks so it isnt perfectly synced)
  • DESIRE: it would be awesome if some of these dummy units died off (and respawned) in relation to the parent units health --- but this is probably way too difficult to achieve

Issues:

  • dont want to be able to select dummy units. But when i give them the locust ability (to disable selection), i no longer can grab hold of them in trigger editor by selecting units in region
  • dont want these units to get bugged by collisions --- even setting collision size 0 they still collide with structures
  • dont want the units to start flying (raised height) which occurs if i give them "fly" as movement type and they move over a structure--- as an attempt to overcome the issue of colliding with structures i wrote above
  • dont want these units to accidentally lose their parent --- currently I just am trying to make this work by selecting units in area around main unit, that match the dummy unit type. But if 2 different main units got close to eachother, they'd steal dummy units from the other one

Possible Solution (I cant make work):

  • add multiple units together in retera studio... find a way to make it so their attack animations are all shared in 1 "attack" but with each attacking at slightly different times
  • this gets super janky and the imported unit uses bone connections to nodes from previous unit so they look like absolute monstrosities.
  • even if this wasnt super janky --- when the unit turns, all the grouped units would just rotate around main unit, rather than rotating in spot

This would be the ideal solution, because it would basically avoid the need for all triggers. and would make there be less units putting strain on CPU. However, I doubt its possible given the last bullet point i added there


What I have done so far: (just trying to make it work for 1 dummy unit currently)
  • place
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Unit-type of (Picked unit)) Equal to Footman_0_0
            • Then - Actions
              • Set VariableSet TempLoc = (Position of (Picked unit))
              • Set VariableSet TempLoc = (TempLoc offset by 100.00 towards 0.00 degrees.)
              • Unit - Create 1 Footman_Scut for Neutral Passive at TempLoc facing (Facing of (Picked unit)) degrees
              • Unit - Change color of (Last created unit) to (Color of (Owner of (Picked unit)))
              • Custom script: call RemoveLocation(udg_TempLoc)
            • Else - Actions
----------------------------------

  • Smart
    • Events
      • Unit - A unit Is issued an order targeting an object
      • Unit - A unit Is issued an order targeting a point
    • Conditions
      • (Issued order) Equal to (Order(smart))
      • (Unit-type of (Triggering unit)) Equal to Footman_0_0
    • Actions
      • Set VariableSet TempLoc = (Position of (Triggering unit))
      • Unit Group - Pick every unit in (Units within 150.00 of TempLoc.) and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • (Unit-type of (Picked unit)) Equal to Footman_Scut
            • Then - Actions
              • Set VariableSet Temp_Location_Farm = (Target point of issued order)
              • Unit - Order (Picked unit) to Move To (Temp_Location_Farm offset by 100.00 towards 0.00 degrees.)
              • Custom script: call RemoveLocation(udg_Temp_Location_Farm)
            • Else - Actions
      • Custom script: call RemoveLocation(udg_TempLoc)
----------------------------------

NOTE:
  • I made them spawn for neutral passive to make it so i couldnt give them orders manually (by selecting and right clicking or ETC) since the "locust" strategy wasnt working.
  • Currently this sort of works for just moving the unit using right click. However it stops working if it collides with a structure --- also need to make a different version for when you give order with a unit as target because right now if i right click a unit, it doesnt know what "target point of issued order" is
  • ignore variable name "Temp_Location_Farm". I plan to make better variables when i get something working. Right now i am just utilizing a previous variable to just try and get something working.


I have some for "attack" as well, but it currently just moves them --- so its basically identical to "Smart"

I am really hoping someone has already done this --- but i have no idea what to search to find out (typing in unit group obviously just gives references to the unit-group triggers)
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
For your specific setup you'll probably want to store these Dummy units in a Unit Group or save them in a Hashtable at the time of creation. Then link the "leader" to the data structure so that you can easily reference all of it's "followers" at any given moment.

Here's the Unit Group example in combination with a Unit Indexing technique to link units and data together:
  • Leader Move Order
    • Events
      • Unit - A unit Is issued an order targeting a point
    • Conditions
      • Is_A_Leader[(Custom value of (Triggering unit)] Equal to True
      • Or - Multiple conditions
        • (Issued order) Equal to (Order(smart))
        • (Issued order) Equal to (Order(move))
    • Actions
      • Set Variable Leader = (Triggering unit)
      • Set Variable Leader_CV = (Custom value of Leader)
      • Set Variable Temp_Loc[0] = (Target point of issued order)
      • -------- --------
      • Unit Group - Pick every unit in Leader_Group[Leader_CV] and do (Actions)
        • Loop - Actions
          • Set Variable Follower = (Picked unit)
          • Set Variable Follower_CV = (Custom value of Follower)
          • Set Variable TempLoc[1] = (Temp_Loc[0] offset by Follower_Offset[Follower_CV] towards Follower_Angle[Follower_CV] degrees.)
          • Unit - Order Follower to Move To Temp_Loc[1]
          • Custom script: call RemoveLocation( Temp_Loc[1] )
      • -------- --------
      • Custom script: call RemoveLocation( Temp_Loc[0] )
Is_A_Leader is a Boolean array variable that's linked to the Leader. It will be set to True the moment the Leader is created.
Leader_Group is a Unit Group array variable that's created and linked to the Leader as well.
Follower_Offset and Follower_Angle are Real array variables that will be linked to each Follower at the time of creation.
I turned TempLoc into an Array called Temp_Loc just to make it easier to work with. You also had some memory leaks when using Point With Polar Offset.

Here's an example of creating a leader (Paladin) with 6 followers (Footman):
  • Actions
    • Set Variable Temp_Loc[0] = (Center of playable map area)
    • Unit - Create 1 Paladin at Temp_Loc[0]
    • Set Variable Leader = (Last created unit)
    • Set Variable Leader_CV = (Custom value of Leader)
    • Set Variable Is_A_Leader[Leader_CV] = True
    • Custom script: set udg_Leader_Group[udg_Leader_CV] = CreateGroup()
    • -------- --------
    • -------- Create the followers in a formation: --------
    • For each integer (LOOP) from 1 to 6 do (Actions)
      • Loop - Actions
        • Unit - Create 1 Footman at Temp_Loc[0]
        • Set Variable Follower = (Last created unit)
        • Unit Group - Add Follower to Leader_Group[Leader_CV]
        • -------- --------
        • -------- Move the follower to it's designated position in the formation: --------
        • Set Variable Follower_CV = (Custom value of Follower)
        • Set Variable Follower_Offset[Follower_CV] = 128.00
        • Set Variable Follower_Angle[Follower_CV] = (Real(LOOP) x 60.00)
        • Set Variable Temp_Loc[1] = (Temp_Loc[0] offset by Follower_Offset[Follower_CV] towards Follower_Angle[Follower_CV] degrees)
        • Unit - Move Follower to Temp_Loc[1]
        • Custom script: call RemoveLocation( Temp_Loc[1] )
    • -------- --------
    • Custom script: call RemoveLocation( Temp_Loc[0] )
How the Unit Indexer works here:

The Unit Indexer automatically assigns a unique Custom Value to each of your units when they first come into play (or if they're already preplaced on the map). We're taking advantage of this by using Custom Value as the [index] of our Array variables. The result is that each individual Unit can have their own Value inside of an Array, all you have to do is plug their Custom Value into the [index] like you see me doing with Is_A_Leader[], Leader_Group[], Follower_Offset[], and Follower_Angle[].

But I left out an important step. The Unit Indexer will recycle Custom Values that are no longer being used (like when a unit dies). Because of that you should destroy the Leader_Group and set Is_A_Leader back to False whenever a Leader dies. Otherwise, a newly indexed unit may inherit a dead Leader's data, resulting in a random Peon being marked as a Leader (True) even though they're not supposed to be one.

Oh and for collision you can try turning it off like this:
  • Unit - Turn collision for (Last created unit) Off
Also, here's a somewhat similar system:
 
Last edited:
Top