Abnormal202 Scripting Tutorial 8: Arrays

broken avatar :(
Created 84 days ago
by qwerty195
0 Members and 1 Guest are viewing this topic.
166 views
broken avatar :(
×
broken avatar :(
Location: usU.S.A! U.S.A!
Date Registered: 10 June 2015
Last active: 63 days ago
Posts
86
Respect
Forum Rank
Rotting Walker
Primary Group
Community Mapper
My Groups
More
My Contact & Social Links
More
Personal Quote
Abnormal202
Signature
-Abnormal202
×
qwerty195's Groups
Community Mapper Has released one or more maps to the UGX-Mods community which have been added to the UGX Map Manager.
ABNORMAL202 SCRIPTING TUTORIAL 8: ARRAYS
See ALL Tutorials

DESCRIPTION

Arrays are an essential part to programming, and for me, they were one of the biggest hurdles for scripting. So take this tutorial slowly, read it over multiple times if you have to, but I will try to do my best to explain them.

CREATING AN ARRAY

Arrays are basically a way of storing multiple entities inside one variable. You can define an array multiple ways:

defining it like this:
watermelons = [];
and then adding the respective elements to the arrays like this:
melon_0 = GetEnt("watelon","targetname");
watermelons[0] = melon_0;
OR
by using array functions that return/create arrays for you:
melon_phrases = array( "green & red, big as my head","round and plump, give me some","hard yet soft, let me crunch");
watermelon_triggers = GetEntArray("melon_trigger","targetname");
Don't worry about understanding all of the above just yet; just wanted to show how there are multiple correct ways to create an array and you may encounter all of these.

PARTS OF AN ARRAY

One of the most common ways arrays are used is for grabbing multiple ents with a common targetname using GetEntArray().
For example, if I had script_model with the targetname: "watermelon", I could grab it using:
melon = GetEnt("watermelon", "targetname");
Now I have that one model stored in the variable I called "melon". But what if I wanted to grab more than one watermelon with that targetname? GetEnt() will not work if more than one entity has the targetname it's looking for, because it doesn't know which ent you want.
So instead I can use:
melons = GetEntArray("watermelon", "targetname");
this will find all entities with the targetname "watermelon" and store them in an array, which is stored in the variable "melons". Notice how I pluralized this variable as opposed to just calling it melon like the above. This is because I want to think of it as multiple entities instead of one.
Let's say in this example there were 3 models with the targetname "watermelon". That means there are 3 entities in the array and we can access each one like this:
melon_0 = melons[0];
melon_1 = melons[1];
melon_2 = melons[2];
notice:
  • an array counts starting at 0, not 1. So even though there are 3 entities, they're essentially labeled 0,1,2.
  • the [ ]
  • the number inside the [ ]. This number is known as the index. the index goes as high as the size of the array, minus one (due to starting at 0). When using GetEntArray() each melon entity is stored at a certain index. One model will be index 0, a different one will be index 1, and so on. Due to not knowing how the computer decides which script_model goes first, then next, etc. the entities and their respective indexes will essentially be random using GetEntArray(), however there are other situations in which you can decide which index an entity will be under.
this concept of the index is important to understand, because it's essentially the only way we can interact with the actual entities in the array. 
For example this would Not do anything:
melons MoveZ(50, 2);
but this will:
melons[0] MoveZ(50, 2);
A very handy thing to know: Arrays always have a property stored on them called size, that is how big it is, or how many entities are stored inside it. You can access it like this:
amount_of_melons = melons.size;
this is very neat because the size of the current array will always be what the next index value would be if another entity were to be added to it. In our example with the 3 melons, the size of the array would be 3, and the already used indexes are 0,1, and 2 - so the next value of the index would be 3, same as our size.

FOR LOOPS

For loops can be used for many things, but they're mostly used in conjunction with arrays, which is why I have waited until now to talk about them. A For loop is basically a while loop that automatically stops after a certain amount of times, by checking a variable.
This is what a common For Loop might look like:
for(i=0; i<10; i++)
{
   
}
Notice:
  • the word for
  • the ()
  • the init. In this example it is i = 0. This is where we define a variable and set it to something, typically a number, and often 0. Usually people call the variable "i", but it could be anything.
  • the condition. In this example it is i < 10. This is where we put a condition that has to be true in order for the For Loop to loop again. In this case it will keep looping as long as i is less than 10, but if it were to say, equal 10 or something higher, the loop would stop running and the code below it would activate.
  • the increment. In this example it is i ++. This code will occur at the end of every loop of the For Loop. So in this case, i will start as 0, then for the next loop it will equal 1, then 2, etc. However when i = 9 the next loop will not occur because adding 1 to i would make it equal to 10, which is not < 10, ending the For Loop.
  • the ; in between the init & condition, and in between the condition & increment.
  • the {}. In between these is where, similar to while loop, the code we want to loop occurs.
Using the concept of a For Loop, we can easily perform actions to all entities in an array at once. For example:
for(i=0; i<melons.size; i++)
{
   melons MoveZ(50, 2);
}
Notice:
  • I'm using melons.size as what I want i to always be less than in order to keep looping. Because the .size will always be one more than the last index of the array, this means the for loop will run once for every entity in the array.
  • for the index I'm using i. Every time the code inside the for loop is run it will substitute the current value for i inside there. so the first loop around it will be melons[0] than melons[1] etc.
  • I don't need to have a wait in my For Loop. This is because it is not being run infinitely unlike the while loops, so it will not freeze the computer from me trying to run it without rest.
This above array will successfully move all script_models part of the melons array 50 units higher in 2 seconds. While it may seem like it took a lot of code just to do that, the great thing about it is the flexibility. This code will work no matter how many models I have with the targetname: "watermelon" on them in radiant. This makes it so much more efficient and professional than:
melon_0 = GetEnt("watermelon_0", "targetname");
melon_0 MoveZ( 50, 2);
melon_1 = GetEnt("watermelon_1", "targetname");
melon_1 MoveZ( 50, 2);
melon_2 = GetEnt("watermelon_2", "targetname");
melon_2 MoveZ( 50, 2);

FOREACH LOOPS

Whereas For Loops can have use outside of arrays, Foreach loops are designed specifically for arrays. Though a for loop can accomplish anything a Foreach loop can (and not vice versa), foreach can be a great alternative, which will save a lot of typing and look nicer.
Here is a foreach loop that accomplishes the exact same thing as the above For Loop:
foreach(melon in melons)
{
   melon MoveZ( 50, 2);
}
Notice:
  • the word foreach (don't forget it's all one word)
  • the ()
  • the 1st word, melon. We can call this whatever we want, but this will represent each item in the array. We must use the same word we set for it inside the () as inside the {} to reference the entity in the array.
  • the word in.
  • the 2nd word, melons. This must be an already defined array, and it will be the array that foreach will loop every entity inside of through the code in the {} below.
The foreach code is much cleaner, easier to remember, and less likely to screw up when typing. However, there are certain limitations with this format, as there is no longer any sort of variable being incremented with each loop. This means that if we, say, wanted to do something special when the 2nd melon is moved we would have to use a For Loop:
for(i=0; i<melons.size; i++)
{
   if(i == 1)
   {
      IPrintLnBold("I'm a special Melon, who must be higher than the others");
      melons MoveZ(70, 2);
   }
   else
   {
      melons MoveZ(50, 2);
   }
}
Because there is no variable "i" we can check with foreach loops.

ADDING TO/REMOVING FROM AN ARRAY

Thankfully, our arrays are not set in stone once we create them. We are always able to add values to them or remove values from them using the below functions:
ArrayInsert(, , );
ArrayRemoveIndex(,,[preserve_keys]);
ArrayRemoveValue(,,[preserve_keys]);
Note that using ArrayRemoveValue() will remove any of the value you put that is in the array, no matter the index, meaning it can remove more than one item from the array at once if they are the same value.
There are even more useful array functions, and since a lot of them are engine functions, you can find them in the Modme ScriptDocs. I feel the above functions are pretty self-explanatory, so I won't spend any more time on them.

NON-ENTITY ARRAYS

Though probably most of my use of arrays comes the function GetEntArray(), there are plenty of useful ways to use arrays that aren't necessarily of objects in radiant.
For example we might want to create an array of strings, and we can't use GetEntArray() to accomplish that, so instead we use:
melon_phrases = array( "green &amp; red, big as my head","round and plump, give me some","hard yet soft, let me crunch");
note that this will preserve the order the strings were put in, so the "green & red" phrase will be at index 0, the "round and plump" phrase will be at index 1, and the "hard yet soft" phrase will be at index 2.
This means if I were to use a For or Foreach Loop, I would know exactly what order these strings would be run in:
foreach(phrase in melon_phrases)
{
   IPrintLnBold(phrase);
   wait(4);
}
If I wanted to randomize the order however, I could use a handy function from array_shared.gsc (#namespace array) called randomize():
randomized_array = array::randomize( original_array );
Speaking of random, what if I wanted to just use one random value from an array, instead of all of them in a random order? Since indexes are always integers, I can use:
integer = RandomInt();
like this:
random_integer = RandomInt(melon_phrases.size);
IPrintLnBold(melon_phrases[random_integer]);
While RandomInt() definitely has uses outside of arrays, I feel it is important to point out as I commonly use it with arrays. It will always return a value from 0 to the number you put in minus 1, so it feels designed for putting an array's size in there, because as I have mentioned before an array's size will always be 1 more than the last used index in the array.
There are still plenty more cool things you can do with arrays, and I can't point out all of them, so you'll just have to find them yourselves. I know arrays can be confusing, but they are an absolute must to understand if you wish to create more efficient code.
See ALL Tutorials


 
Loading ...