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

[Trigger] Loops and Arrays tutorial

Status
Not open for further replies.
Level 29
Joined
Jul 29, 2007
Messages
5,174
Loops and arrays tutorial (also containing some information about leaks)




- Loops and arrays -


A loop is basicly what it sounds like, a circle that never ends, or in our case, it ends when we order it to end.

A loop in the World Editor would look like this

  • For each (Integer A) from X to Y, do (Actions)
    • Loop - Actions

X is a number, and Y is a number.

Normaly, the numbers won't matter. if you are making a loop that will run from 5 to 10, or from 10 to 15, in both cases it would run 5 times.
You may ask "why are there 2 numbers at all ?", and I will answer.
The huge bonus of using loops, is that you can assign Variables with Arrays, to the loop.

A small explanation on variables and arrays:

A variable is basicly just a name, untill you put a value in it.
For example, a Unit variable will be equal to - no unit (nothing) - untill you put a unit value or another variable's value into it.

Arrays are what they sound like, a few layers of variables (like a onion).

[Tip] in the world editor, you would most likely want to set array values to 1, allowing you to use about 8200 of them

Each array is like a diffrent instance of the variable. If you have a variable thats called Unit, and you put arrays, you can then make Unit[0] (the first array is -0- not 1), Unit[1] and so on.

"So, whats the diffrence then just making a few variables ?"
The first noticable diffrence, is that you will need to use less variables, and by that make your map a bit less messy.

But a huge diffrence is using arrays with the loops, and here I go back to the main explenation.

You can write a trigger that will go like this
  • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
  • Set Unit1 = (Last created unit)
  • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
  • Set Unit2 = (Last created unit)
  • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
  • Set Unit3 = (Last created unit)

This trigger created 3 footman for player 1, and set the three of them into three diffrent Unit variables, the arrays way to make this, would be like this

  • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
  • Set Unit[1] = (Last created unit)
  • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
  • Set Unit[2] = (Last created unit)
  • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
  • Set Unit[3] = (Last created unit)

Now, as you can see, the only diffrence is the ammount of variables used (3, and 1).

The third way, would be using a loop for this.
This will be the first example using arrays with the benefits of a loop

  • For each (Integer A) from 1 to 3, do (Actions)
    • Loop - Actions
      • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
      • Set Unit[(Integer A)] = (Last created unit)

This loop will run from 1 to 3 meaning, it will run through 1, then 2, then 3, and will create our 3 footman again, just this time it sets the arrays by the loop's value.
This means that if the loop will run now the value of 1 (the first time in this loop), it will set the last created unit into Unit[1].
If we made a loop from 30 to 40, it will set the the last created unit to Unit[30].

This is very useful if you need to set a lot of objects and you don't want to make a new line of code for each one.

Now, another very useful benefit of the this, would be using a variable we set.

Lets go back to our three fresh footman.

You just set them to their three arrays, and now you want to order them to do something.
You can either order him as you always did like this

  • Unit - Order Unit[1] to Move To (Center of (Playable map area))
  • Unit - Order Unit[2] to Move To (Center of (Playable map area))
  • Unit - Order Unit[3] to Move To (Center of (Playable map area))

Or you can move them by the new technic you have just learnt, like this

  • For each (Integer A) from 1 to 3, do (Actions)
    • Loop - Actions
      • Unit - Order Unit[(Integer A)] to Move To (Center of (Playable map area))

[Hint] If you have no wait actions in a loop, it would do it so fast that it will look to our human eyes as if it did it all at the same instance.


So, now we orderd them to move to the middle of the map with 2 lines of codes (the loop and the action) instead of 3, a pretty small diffrence... but again, if you would set for example 10 units (for 10 players),
it would be pretty annoying to set them all variables, and then order them all to do something.

Now ill go to more advanced uses of the loop.

If you have ever created custom skills, you probably set a lot of Point variables.
If you have made advanced custom skills, you have probably used A LOT LOT LOT of Point variables.
Wouldn't you wish to set them all in a few lines of code, instead of a line for each, and a line for removing them ? ([Notice] removing points and leaks will be discussed later, just as a add for this tutorial)

If you for example want to make a dummy unit (Dummy Unit Definition: A unit that is not going to play and in most cases will do a action and then get removed from the game) to circle around your hero,
or just a special effect, again to circle around your hero, you would need to set as much points as you want around your hero.
This would be done by first creating a arrayed Point variable and then use this trigger

  • Actions
    • Set point[0] = (Position of (Triggering unit))
    • Set point[1] = point[0] offset by 256.00 towards 0.00 degrees)
    • Set point[2] = point[0] offset by 256.00 towards 72.00 degrees)
    • Set point[3] = point[0] offset by 256.00 towards 144.00 degrees)
    • Set point[4] = point[0] offset by 256.00 towards 216.00 degrees)
    • Set point[5] = point[0] offset by 256.00 towards 288.00 degrees)
    • ------ Put your actions here ------

Notice that the reason I set Point[0] first and then based all of the others on it, will be explain later in the "Point removing and leaks" section.

This circle is made of 5 points (can hardly call it a circle really), and needed 5 lines of code.
Now in arrays it will look like this

  • Actions
    • Set point[0] = (Position of (Triggering unit))
    • For each (Integer A) from 1 to 5, do (Actions)
      • Loop - Actions
        • Set point[(Integer A)] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards (72.00 x (Real((Integer A)))) degrees)
        • ------ Put your actions here ------

Notice that 72 x Integer[A].

I think this pretty much sums the usages of arrays.
From here its your own imagination :)




- Point removing and leaks -

This is only partialy connected to the loops.
As I mentions, when creating custom skills, you will most likely use A LOT of Points.
Now, each time you set a point variable to some value, it DOESN'T remove the old one ! it just ignores it and lets it stay there, sleep, get fat, and... steal your computer's memory usage.
For other variables, such as Integers, Reals, and most of them, this doesn't happens.
The 2 largest cases are Points and Unit Groups.

So, basicly every time you set a Point variable or a Unit Group, you will need to later on remove them.


[Removing Points]


The main code to remove a point would look like this

  • Custom script: call RemoveLocation(udg_VariableName)

[Hint] the Custom Script action is the third action in the trigger editor !
[Hint] Custom Scripts are case sensitive ! UPER CASES are UPER CASES and lower cases are lower cases
For example, if your Point is called "My_Point", the custom script will look like this
  • Custom script: call RemoveLocation(udg_My_Point)

If you have a array, it would just be (udg_VariableName[array])

For example
  • Custom script: call RemoveLocation(udg_My_Point[1])

If you need to find out what is the code for a Integer[A/B] loop, or for anything else that you don't know, you should make a action that will involve that thing,
For example

"Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards (72.00 x (Real((Integer A)))) degrees)"

Create that at a NEW trigger, then go to Edit, and click on "Convert To Custom Text".
You will now see a totaly new thing, thats the famous JASS.
It would look like this

Code:
function Trig_Sliding_dark_Actions takes nothing returns nothing
    set udg_point1[1] = PolarProjectionBJ(PolarProjectionBJ(udg_point1[0], 100.00, 0.00), 256, ( 72.00 * I2R(GetForLoopIndexA()) ))
endfunction

//===========================================================================
function InitTrig_Sliding_dark takes nothing returns nothing
    set gg_trg_Sliding_dark = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Sliding_dark, function Trig_Sliding_dark_Actions )
endfunction

Now the part we are interested in, is this "GetForLoopIndexA()".

So if you want a point with integer[A] as a array, you would need to remove it with this code

  • Custom script: call RemoveLocation(udg_My_Point[GetForLoopIndexA()])
And yes, those () are needed.

[Notice] in the example of the circle I made up there, I made first a point at the position of the unit, and only after that I based the circle points on the first point.
This is, also the position of unit leaks, and also the point after the position of unit leaks.


[Unit Groups leaks]


Unit groups leak exacly the same way, so every time you set a unit group, either to a variable, or without a variable, you will need to later on remove it.

There are two ways removing unit groups.
One is with this custom script

  • Custom script: set bj_wantDestroyGroup = true

This will order the group to be destroyed after it finished its actions.
In case you need the group also for other actions and triggers, and only later on you want to destroy it, use the second way.

The second way is seting a unit group into a Unit Group variable, doing all the actions you want with it, and then destroying the variable with this script

  • Custom script: call DestroyGroup(udg_VariableName)
If your group variable is called Group for example, it would be "Custom script: call DestroyGroup(udg_Group)



For more information about leaks go to the first sticky in the Triggers forum (here) called "Things That Leak".


Hope this helped,
The end :p
 
Last edited:
Level 21
Joined
Aug 21, 2005
Messages
3,699
1) Whether people look at the tutorial section or not, this thread belongs there, not here.
2) It looks chaotic. Try creating some structure. For instance: Start with giving your different parts titles, such as:

A) Loops (font size 20?)
B) Arrays (font size 20?)
C) Combining them (font size 20?)
D) Removing leaks (font size 20?)

These categories might contain subdivisions such as

A) Loops (font size 20?)
1) What is a loop, why would I use one? (font size 15?)
2) How does it work? (explaining the actual triggers)
3) An example
4) Hints

3) Tutorials on leaks have been done many times before, I suggest you just stick to loops/arrays; ofcourse explain why you add a certain custom scripts (for deleaking) and link to another tutorial that fully covers deleaking methods.
 
Level 9
Joined
May 27, 2006
Messages
498
  • Actions:
    • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
    • Set Unit[1] = (Last created unit)
    • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
    • Set Unit[2] = (Last created unit)
    • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
    • Set Unit3[3] = (Last created unit)

You forgot to delete the "3" in the last line

And for your trigger about polar projections and circles, you`d add a hint between each "Set point[1] = ..." explaining to add own actions. Because just setting variable and dont using it gives no benefits, or there is some hidden sense? :)

Very possible that noone will understand that what i`ve just said (xD), so look at this:
  • Actions:
    • Set point[0] = (Position of (Triggering unit))
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 0.00 degrees)
    • (your action[s])
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 0.00 degrees)
    • (your action[s])
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 72.00 degrees)
    • (your action[s])
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 144.00 degrees)
    • (your action[s])
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 216.00 degrees)
    • (your action[s])
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 288.00 degrees)
    • (your action[s])

And anyway, good tutorial that may help many people ;P
 
Last edited:
Level 29
Joined
Jul 29, 2007
Messages
5,174
You forgot to delete the "3" in the last line

Fixed :p

And for your trigger about polar projections and circles, you`d add a hint between each "Set point[1] = ..." explaining to add own actions. Because just setting variable and dont using it gives no benefits, or there is some hidden sense? :)

Very possible that noone will understand that what i`ve just said (xD), so look at this:
  • Actions:
    • Set point[0] = (Position of (Triggering unit))
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 0.00 degrees)
    • (your action[s])
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 0.00 degrees)
    • (your action[s])
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 72.00 degrees)
    • (your action[s])
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 144.00 degrees)
    • (your action[s])
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 216.00 degrees)
    • (your action[s])
    • Set point[1] = ((point[0] offset by 100.00 towards 0.00 degrees) offset by 256.00 towards 288.00 degrees)
    • (your action[s])


Lol ! you noticed that but you didn't notice they are all "set point[1]" and also the continuation is bugged... anyway fixed it :p

.
2) It looks chaotic. Try creating some structure. For instance: Start with giving your different parts titles

Actualy I did pretty much add titles.
 
Level 19
Joined
Aug 24, 2007
Messages
2,888
someone wants +rep again

to get +rep
make some model with milkshape and post on models section
I mean post the screen shot so you wont need to make animations etc
 
Status
Not open for further replies.
Top