Chapter 3 - Variables and Types

From Frictional Wiki
Jump to navigation Jump to search

The very first thing that a programmer needs to know about programming is the concept of variables. If you've taken an algebra class in the past, the term may sound familiar, which is helpful as variables in algebra and variables in programming are similar.


Imagine that you needed to write a program that took some numbers and added them up. The first thing you would want to do is to tell the program what those numbers are. Say you told the program the numbers 3, 7, 2, 8, and 5. Well, the program is going to need a way to remember those numbers so that it can work with them later on.

This is where variables come in. A variable is a construct in a program that is designed to hold a value and store it under a label. For example, take a look at the following code.

    int x = 5;

Let's break this down. The int is telling the program what type a variable is, the x tells the program that the variable's name is x, and the the = 5 tells the program what the variable's value is. In short, this line of code creates a new variable x of type int and gives it the value of 5.

There are two things going on in this code. The first is that a variable is being declared, which means that the program is creating a new variable to remember. The second is that a variable is being initialized, which means a variable is being assigned a value for the first time.

Now that our variable has been created (declared), we can access it elsewhere in our program. If, say, we wanted to assign a different value to it, we could do the following:

    int x = 5;
    x = 3;

Note that the int is gone from the second line. int is only required when declaring a variable for the first time. After that, the program knows what the type of x is, so you don't need to keep telling it.

You can also use variables when assigning a value to other variables:

    int x = 5;
    int y = x;

In this code, we create a variable x and assign it a value of 5. Then we create another variable y and assign it a value of x. This means that we take whatever value is being stored in x and copy it into y. At the end of this code, y will also be set to 5.

Note icon.png Before, I talked about declaring and initializing a variable and how it was convenient that you could do both on the same line of code. It is not necessary to do so, however, and in some situations, you may want to declare a variable without immediately initializing it. You can do that in the following way:

    int x;
    x = 5;

See how the first line doesn't assign a value to the variable x? This is a declaration without an initialization. The value of a variable that has been declared but not initialized is the default value of the type assigned to the variable, which, in this case, is 0 due to the type being int.


The technical term for the name of a variable is an identifier. In general, you can name your variables whatever you want, but there are a number of rules and recommendations for how you do it.

First, the identifier must start with a letter in the alphabet (uppercase or lowercase) or an underscore character _. Any identifier that starts with a number or other symbol will not be recognized and will cause an error in your script. After the start of the variable, you may use letters or numbers as well as an underscore character. You cannot use a space as part of a variable name.

// These are legal identifiers.
int abcdef;
int aBcDeF;
int _abcdef;
int abc123;

// These are not legal identifiers.
int 123456;
int 123_456;
int 123abc;
int %$#^%^%;
int abc def;

Second, the identifier cannot be one of a number of specific words. These words are called keywords, and they are reserved by AngelScript to mean various things. The full list of keywords are:

and abstract auto bool break
case cast class const continue
default do double else enum
false final float for from
funcdef function get if import
in inout int interface int8
int16 int32 int64 is mixin
namespace not null or out
override private protected return set
shared super switch this true
typedef uint uint8 uint16 uint32
uint64 void while xor

Following those two rules, you can otherwise name your variables whatever you like. However, a recommendation (a "soft-rule", if you will) is that you name your variables with an identifier that has to do with that variable's purpose. For example, if you have a variable that stores the water level in a pool, you might name it WaterLevelInPool. While giving your variables ambiguous or nonsense names won't result in an error, it will result in your code being incredibly difficult to read and understand, even by you.

// Good variable names
int WaterLevelInPool;
int ExplosionCount;
int NumberOfKills;
int DistanceToLocation;

// Bad variable names
int a;
int vakjnaldkjbv;
int _________;

(While as a general rule it's a bad idea to give single letter names to variables, it is acceptable to do so in situations where the variable is used in a temporary setting.)

Note icon.png In addition to this, HPL3 recommends a particular convention for naming variables. It involves prefixing the name of a variable with letters that signify both its type and its scope (more on scopes in Chapter 8). For example, if I had an int variable named count that existed on the class scope, then I would call it mlCount. For a list of the prefixes, see this page on the wiki.

Variable Types

When we talk about a variable's type, we are referring to the kind of value or information that value stores. So far, whenever we've declared a variable, it's been with the type int, which means that the variable stores a number of some description. There are quite a few different types to choose from, however, and which one you decide to go with depends on the role a particular variable will play and what kind of value it will store.

Built-In Types

There are a number of types that are built-in with AngelScript. You can expect to find these types no matter which game you are programming for as long as you are using AngelScript.

Let's start with the integral types of AngelScript. These types are meant to hold numbers without decimal points.

Type Name Value Range Default Value
int8 -128 to 127 0
int16 -32,768 to 32,767 0
int -2,147,483,648 to 2,147,483,647 0
int64 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 0
uint8 0 to 255 0
uint16 0 to 65,535 0
uint 0 to 4,294,967,295 0
uint64 0 to 18,446,744,073,709,551,615 0

These types are categorized based on two factors: size, and signedness.

  • The size of a type is how much memory it takes up in the program. This size is generally measured in bits. An int8, for example, uses 8 bits to store its value, whereas an int64 uses 64 bits. (The int and uint types use 32 bits, but as 32 bit the most frequently used size, the 32 part of the names have been chopped off for the sake of convenience.)
Note icon.png In computer memory, one bit is one switch in the computer's memory that can either be on or off. This is considered to have a value of 1 (on) or 0 (off). Stringing these bits together, you can use different combinations of bits to refer to larger and larger values. This is known as the binary system. You can learn more about the binary system here.
  • The signedness of a type is whether or not the values in the type can have a sign, or, in other words, whether or not the type supports negative numbers. If you compare int8 and uint8, you'll see that the range of int8 is -128 to 127, whereas the range of uint8 is 0 to 255. The number of possible values in both cases is still the same (256 possible values), but the "signed" type has been shifted over so that 0 is in the middle of the range instead of the beginning.

Next, we have what are known as the floating-point types. These types are for representing numbers with decimal points.

Type Name Value Range Smallest Positive Value Maximum Number of Digits Default Value
float +/- 3.402823466e+38 1.175494351e-38 6 0.0
double +/- 1.79769313486231e+308 2.22507385850720e-308 15 0.0

You can see from the table that the floating-point types aren't quite as straight-forward as the integral types. Instead of a nice clean minimum and maximum value, we have a bunch of decimal numbers in scientific notation. This has to do with how floating-point types are stored in memory. That topic is fairly advanced, so I won't go over it here, but if you're curious, the process is described here.

The size of a float is 32 bits, whereas the size of a double is 64 bits. Size is a factor in floating-point types as well, but instead of being for the range of the value (although that is affected too), the size of a floating-point type has to do with its level of precision. As you can see in the table, the maximum number of digits you can use is 15 digits for a double, but only 6 digits for a float. These aren't hard limitations, however, but merely guarantees of accuracy. If you were to use a float value with more than 6 digits, say, 1234.5678, the program cannot guarantee the precision of that number. If you were to check that number while the program was running, it might have an actual value of the number might actually be something like 1234.562. This is because of rounding errors. The reason for it, again, has to do with how floating-point numbers are stored in memory, but you don't need to worry about the details too much. As long as you stay within the recommended number of digits, it should never be a problem.

Note icon.png The general rule for which type you should use is to use the smallest type that your application will allow. For example, if you know you are never going to deal with values less than 0 or greater than 255, then the uint is a great choice for your variable's type. That being said, the AngelScript runtime within HPL3 is optimized to use numerical types with 32 bits, so the general recommendation is to use int, uint, or float whenever possible.

There is one more built-in type for AngelScript, and it has nothing to do with numbers:

Type Name Possible Values Default Value
bool true, false false

The bool type name is short for boolean. Boolean values are restricted to one of two values: true or false. Booleans have to do with whether something is or is not. For example, some boolean variables you might store could be:

bool IsLightOn = true;
bool HasPlayerEnteredArea = false;
bool DidILeaveTheOvenOn = true;

Special Types

Beyond the built-in types of AngelScript, there are a number of other types that are specific to HPL3. If you were to go to another game that uses AngelScript (such as Wolfire's Overgrowth), chances are that that game's modding system won't have these types available (though it's possible they will have equivalents).

Type Name Possible Values Default Value
tString "value" <Empty>

In HPL3's AngelScript, a tString is a specific flavor of a string, which is a sequence of characters, letters, and numbers. It doesn't have a fixed length, so it can be anything from "a" to "Greetings, sirs, my what a lovely fine evening we have here. Might you fancy a cup of tea?".

The most common way to use a tString is to store some kind of word or label, such as when you want to display a message on the screen that the player will read. There are some handy functions that you can use with a tString:

Function Name Description Example
length Gets the number of characters represented by the string. int stringLength = tStringValue.length();
resize Resizes the string to be the specified length. (Removes characters or adds "null" characters as necessary.) tString resizedString = originalString.resize(5);


In addition to variables that store a single value, there is also a type of variable that holds many values. These variables are called arrays.

Some languages allow you to create arrays that can store anything, but in AngelScript, arrays can only hold a single type. This type is chosen when the array is first declared:

array<int> intArray;
array<bool> boolArray;
array<tString> stringArray;

In the above example, the type name inside the angled brackets is the type of value that array can store. For example, the intArray can only store integers, and the stringArray can only hold string values.

That's all well and good, but how do you get at the values in the array? That is done using something called indexer notation. Let me show you how it works:

    lightLevels[0] = 5.0;
    float lightLevel = lightLevels[0];

The square brackets (along with the number inside them) make up the indexer notation. On the first line, we are taking the value 5.0 and storing it in the array at an index (in this case, index 0). The second line we are taking the value in the array at index 0 and assigning it to the variable lightLevel.

You don't have to just use index 0 either. You can use any index you want. A good rule of thumb, however, is to keep your values sequential, which means that if you have 10 values to store, store them in the array at indices 0 through 9.

Note icon.png It might seem odd that I am using index 0 in this example. When I am storing a value in an array at index 0, though, I am storing it in the first index of the array. That's because arrays in AngelScript, like most programming languages, are zero-based, which means the first value is stored at index 0. (One-based arrays might seem more intuitive, but it's easier on the engine if we use zero-based arrays instead, and programmers got sick of doing index - 1 a long time ago.)

In addition to adding a value at a specific index, there are also different ways you can more dynamically access an array. These ways use the array's functions, which we will get into in Appendix 2. For now, these are the more useful functions of an array and how they are used:

Function Name Description
length Gets the number of values stored in the array.
push_back Adds a value to the end of the array. (If indices 0-4 contain values, the new value is stored at index 5.)
resize Resizes the array to t