Arrays
In the previous examples you have learned how to use varialbles for counting and measuring. You have been using one variable to count seconds, another one for frames per second ratio and so on.
But what if you have got a problem that requires a lot of variables to solve?
What if you need tens of variables to hold some temporary values?
In that case, you should use arrays.
An array is a data structure consisting of a collection of element values, each identified by at least one array index. An array is stored such that the position of each element can be computed from its index
Arrays have many applications: they are used to implement mathematical vectors and matrices, as well as other kinds of rectangular tables.Applications use one-dimentional arrays for storing data records. Arrays are also used to implement other data structures, such as lists, queues and strings. Such data structures are used in game applications extensively. It is an essential part of nearly any game application.
When data objects are stored in an array, individual elements are selected by an index that is a non-negative integer. Indices are also called subscripts.
The first element of the array is indexed by subscript of 0. This leads to simpler implementation where the subscript refers to an offset from the starting position of an array, so the first element has an offset of zero.
Arrays can have multiple dimentions too. Thus, it is not uncommon to access an array using multiplt indices.
For example, a two-dimentional array A with three rows and four columns provides access to the element at the 2nd row and 4th column by the expression A[1][3].
Thus, two indices are used for a two-dimentional array, three for a three-dimentional array, and n for n-dimentional one.
Arrays in C++ language
In C++, an array is a variable that can store multiple values of the same type. For example, suppose a class has 27 students and we need to store grades of all of them. Instead of creating 27 separate variables, we can simply create an array:
Here grade is an array that can hold a maximum of 27 elements of double type.
It is also must be remembered that in C++ the size and type of arrays can not be changed after its declaration.
Each element in an array is associated with a number. The number is known as an array index
So let's see how can we access elements of an array... We can access them by using those indices.
There are several things that should be remembered:
- The array indices start with 0. Meaning
x[0]is the first element stored in the array - If the size of an array is
n, the last element is stored at index(n-1) - Elements of an array have consecutive addresses. For example, let's suppose we have an array of integers
int x[10]; the starting address ofx[0]is 0x2120. Then the addres of the next elementx[1]will be 0x2024, the address ofx[2]will be 0x2028 and so on. The address of each element is increased by 4 because it takes 4 bytes to store an integer value in memory.
How do we initialize arrays when application starts?
In C++ language, it is possible to initialize an array during declaration. For example,
or
In the above, we have not mentioned the size of the array. In such cases, the C++ compiler automatically computes the size.
Finally, you can initialize an array with empty members too. In C++, if an array has a size n, we can store up to n number of elements in the array. However, what will happen if we store less than n number of elements?
For example,
Here, the array has a size of 6. However, we have initialized it with only 3 elements. In such cases, the C++ compiler may assign random values to the remaining places. Dependning on version of the compiler, the value may be 0.
C++ allows multidimentional arrays. For example, the following declaration creates a two-dimentioal 5 x 10 integer array:
A two-dimentional array is, in essence, a list of one-dimentional arrays. It can be think as a table, or a matrix which will have x number of rows and y number of columns. Thus, every element in such array is identified by a pair of indices like array[i][j] where i and j are the subscripts that uniquely identify each element in the array.
Similarily to one-dimentional arrays, multi-dimentional arrays can be initialized by specifying bracketed values for each row. The following is an array with 3 rows and each row has 4 columns:
The nested braces, which indicate the intended row, are optional. The following initialization is equivalent to previous example:
Vectors in C++ language
As we've learned above, in C++ an array is a fixed-size collection of elements of the same data type that are stored in a continuous block of memory. Once an array is created, its size can not be changed.
But what if we want to have an array that should changed its size dynamically?
For that, C++ has vectors.
std::vector is a dynamic array that can grow or shrink in size as needed. It is a container class in the C++ Standard Template Library (STL) that provides a convenient way to manage arrays of varying sizes.
One of the key differences between std::vector and arrays is that std::vector manages its own memory allocation and deallocation. When the size of a std::vector changes, it automatically reallocates memory as needed, whereas with an array, you would have to manage the memory manually by allocating or deallocating it yourself.
Additionally, std::vector provides a number of member functions that make it easy to manipulate the elements stored in the vector, such as adding or removing elements, accessing specific elements, and iterating over the vector. With an array, you would have to implement these operations manually.
So to sum up, std::vector provides a flexible and convenient way to work with dynamic arrays in C++, whereas arrays are fixed-size collections of elements that must be managed manually.
Strings in C++ language
In C++, a string is a sequence of characters stored in a contiguous block of memory. Strings can be represented using two different types:
-
C-style strings: C-style strings are arrays of characters terminated with a null character ('\0'). They are created by declaring an array of characters and initializing it with a sequence of characters, followed by a null character. For example:
Strings and ArraysCPPWrapped for easier reading. Turn wrap off to inspect exact line lengths. -
std::string: std::string is a class that represents a string of characters. It is part of the C++ Standard Library and provides a convenient way to manipulate strings. To use std::string, you need to include the <string> header file. For example:
Strings and ArraysCPPWrapped for easier reading. Turn wrap off to inspect exact line lengths.
The main advantage of using std::string over C-style strings is that std::string manages its own memory allocation and deallocation, so you don't have to worry about the size of the string or allocating memory yourself. std::string also provides a wide range of member functions that make it easy to manipulate strings, such as appending or erasing characters, finding substrings, and comparing strings.
In addition, std::string supports a wide range of string operations, such as concatenation, conversion to and from other data types, and input/output.
The example
Now when you've learned all that theory about arrays and strings, let's get to actual example.
In order to demonstrate the work with arrays and strings, we will use several arrays of different dimentions, initialize them with strings and then show these strings on the sides of WOWCube device with a bit of funky animations.
First, let's declare the arrays:
and initialize them:
Pay attention!
Different ways to declare arrays in the code above are used purely for the demonstration purposes. We recommend to choose and use one particular style of string variable declarations in your game cubeapps.
So what exactly is declared here?
arrWOWCUBEdeclares an array of characters that form the word `WOWCUBE'arrWOWCUBE2declares a vector of strings that contains 3 stringsarrTWISTYalso declares a vector of stringsfParamdeclares an array of floating point valuesprefPosdeclares a two-dimentional array of integers that would be used later for storing some temporary values
Second, we need to do some extra initialization. As always, variables are initialized in InitializeResources().
We initialize two timers for animation effects.
Then we modify the on_Timer callback to define the application logic of what should be happening on timer tick.
The function receives timerID identifier of a timer as an input parameter. We have two timers now, and we need to know which one produced a tick, right?
We have two timers that tick with different frequencies - one triggers every 100 milliseconds (10 times a second), another one produces a tick once a second.
So when the first timer ticks, on_Timer(0) is called. And when the second timer ticks, functions parameter changed to 1 and on_Timer(1) gets executed.
So let's see what happens when each timer ticks:
Timer 0
- Take an
i1index fromarrWOWCUBEarray and copy it into a string bufferbuff2 - Increment
i1by 1 - If
i1value gets greater than 7, reset it
Timer 1
- Increment
i2by 1 - If
i2gets greater than 3, reset it
This will result in constant change of array index parameters that we use for composing strings we render on screen.
Finally, we would want to render those strings (with a bit of animation, as promised).
What we have here?
- First screen displays the string buffer
buff2that is dynamically changed every 100 milliseconds on timer 0. - Second screen displays three words from
arrWOWCUBE2array selected by index that gets incremented on timer 1 each second. - Third screen... well, things are getting a little bit tricky here...
Third screen shows the word TWISTY built out of characters stored in arrTWISTY array.
If we would have wanted just to print that word on a straight line, we could just take an index of that array and print all characters one by one, right?
But that would be too easy and too boring. So instead, each letter in the word is animated, it sways up and down leaving a ghostly trace.
Behind every computer animation stands Math.
And our example is not an exclusion - in order to animate word letters we must apply some trigonometry. Cause if we want the letters to sway, we have to find the way to change their coordinates in an endless cyclical manner. And hopefully, make it look neat as well...
So, to generate per-letter vertical offsets, a sinf trigonometrical function is used:
The sinf function in C++ is a math function that calculates the sine of a given angle in radians, where the input value is a single-precision floating-point number. The function is defined in the <cmath> header file.
fParam[i] contains a floating point value of an angle that gets passed to the sine function on every tick and gets incremented by a small value. The offset parameter receives a value of a sine of an angle, then used for rendering letters at dynamic positions.
And finally, three copies of each letter are getting rendered for creation of a ghost trail effect.