Chapter 9: C++ References, Sprite Sheets, and Vertex Arrays

In Chapter 4, Loops, Arrays, Switches, Enumerations, and Functions – Implementing Game Mechanics, we talked about scope. This is the concept that variables declared in a function or inner block of code only have scope (that is, can be seen or used) in that function or block. Using only the C++ knowledge we have currently, this can cause a problem. What do we do if we need to work on a few complex objects that are needed in the main function? This could imply all the code must be in the main function.

In this chapter, we will explore C++ references, which allow us to work on variables and objects that are otherwise out of scope. In addition to this, these references will help us avoid having to pass large objects between functions, which is a slow process. It is slow because each time we do this, a copy of the variable or object must be made.

Armed with this new knowledge of references, we will look at the SFML VertexArray class, which allows us to build up a large image that can be quickly and efficiently drawn to the screen using multiple parts in a single image file. By the end of this chapter, we will have a scalable, random, scrolling background that's been made using references and a VertexArray object.

In this chapter, we will discuss the following topics:

  • C++ references
  • SFML vertex arrays
  • Coding a random, scrolling background

C++ references

When we pass values to a function or return values from a function, that is exactly what we are doing – passing/returning by value. What happens is that a copy of the value held by the variable is made and then sent to the function, where it is used.

The significance of this is twofold:

  1. If we want the function to make a permanent change to a variable, this system is no good to us.
  2. When a copy is made to pass in as an argument or returned from the function, processing power and memory are consumed. For a simple int, or even perhaps a Sprite, this is insignificant. However, for a complex object, perhaps an entire game world (or background), the copying process will seriously affect our game's performance.

References are the solution to these two problems. A reference is a special type of variable. A reference refers to another variable. Here is an example to help you understand this better:

int numZombies = 100;

int& rNumZombies = numZombies;

In the preceding code, we declare and initialize a regular int called numZombies. We then declare and initialize an int reference called rNumZombies. The reference operator, &, which follows the type, determines that a reference is being declared.

Tip

The r prefix at the front of the reference name is optional but is useful for remembering that we are dealing with a reference.

Now, we have an int variable called numZombies, which stores the value 100, and an int reference called rNumZombies, which refers to numZombies.

Anything we do to numZombies can be seen through rNumZombies, and anything we do to rNumZombies we are actually doing to numZombies. Take a look at the following code:

int score = 10;

int& rScore = score;

score ++;

rScore ++;

In the previous code, we declare an int called score. Next, we declare an int reference called rScore that refers to score. Remember that anything we do to score can be seen by rScore and anything we do to rScore is actually being done to score.

Therefore, consider what happens when we increment score like this:

score ++;

The score variable now stores the value 11. In addition to this, if we were to output rScore, it would also output 11. The next line of code is as follows:

rScore ++;

Now, score actually holds the value 12 because anything we do to rScore is actually done to score.

Tip

If you want to know how this works, then more will be revealed in the next chapter when we discuss pointers. But simply put, you can consider a reference as storing a place/address in the computer's memory. That place in memory is the same place where the variable it refers to stores its value. Therefore, an operation on either the reference or the variable has exactly the same effect.

For now, it is much more important to talk about the why of references. There are two reasons to use references, and we have already mentioned them. Here they are, summarized again:

  1. Changing/reading the value of a variable/object in another function, which is otherwise out of scope.
  2. Passing/returning to/from a function without making a copy (and, therefore, more efficiently).

Study the following code and then we will discuss it:

void add(int n1, int n2, int a);

void referenceAdd(int n1, int n2, int& a);

int main()

{

    int number1 = 2;

    int number2 = 2;

    int answer = 0;

    

    add(number1, number2, answer);

    // answer still equals zero because it is passed as a copy

    // Nothing happens to answer in the scope of main

    referenceAdd(number1, number2, answer);

    // Now answer equals 4 because it was passed by reference

    // When the referenceAdd function did this:

    // answer = num1 + num 2;

    // It is actually changing the value stored by answer

    return 0;

}

// Here are the two function definitions

// They are exactly the same except that

// the second passes a reference to a

void add(int n1, int n2, int a)

{

    a = n1 + n2;

    // a now equals 4

    // But when the function returns a is lost forever

}

void referenceAdd(int n1, int n2, int& a)

{

    a = n1 + n2;

    // a now equals 4

    // But a is a reference!

    // So, it is actually answer, back in main, that equals 4

}

The previous code begins with the prototypes of two functions: add and referenceAdd. The add function takes three int variables while the referenceAdd function takes two int variables and an int reference.

When the add function is called and the number1, number2, and answer variables are passed in, a copy of the values is made and new variables local to add (that is, n1, n2, and a) are manipulated. As a result of this, answer, back in main, remains at zero.

When the referenceAdd function is called, number1 and number2 are again passed by value. However, answer is passed by reference. When the value of n1 that's added to n2 is assigned to the reference, a, what is really happening is that the value is assigned to answer back in the main function.

It is probably obvious that we would never need to use a reference for something this simple. It does, however, demonstrate the mechanics of passing by reference.

Let's summarize what we know about references.

References summary

The previous code demonstrated how a reference can be used to alter the value of a variable in one scope using code in another. As well as being extremely convenient, passing by reference is also very efficient because no copy is made. Our example, that is, using a reference to an int, is a bit ambiguous because, as an int is so small, there is no real efficiency gain. Later on in this chapter, we will use a reference to pass an entire level layout and the efficiency gain will be significant.

Tip

There is one gotcha with references! You must assign the reference to a variable at the time you create it. This means it is not completely flexible. Don't worry about this for now. We will explore references further alongside their more flexible (and slightly more complicated) relations, such as pointers, in the next chapter.

This is largely irrelevant for an int, but potentially significant for a large object of a class. We will use this exact technique when we implement the scrolling background of the Zombie Arena game later on in this chapter.

SFML vertex arrays and sprite sheets

We are nearly ready to implement the scrolling background. We just need to learn about SFML vertex arrays and sprite sheets.

What is a sprite sheet?

A sprite sheet is a set of images, either frames of animation, or totally individual graphics contained in one image file. Take a closer look at this sprite sheet, which contains four separate images that will be used to draw the background in our Zombie Arena game:

SFML allows us to load a sprite sheet as a regular texture, in the same way we have done for every texture in this book so far. When we load multiple images as a single texture, the GPU can handle it much more efficiently.

Tip

Actually, a modern PC could handle these four textures without using a sprite sheet. It is worth learning these techniques, however, as our games are going to start getting progressively more demanding on our hardware.

What we need to do when we draw an image from the sprite sheet is make sure we refer to the precise pixel coordinates of the part of the sprite sheet we require, like so:

The previous diagram labels each part/tile with the coordinates and their position within the sprite sheet. These coordinates are called texture coordinates. We will use these texture coordinates in our code to draw just the right parts that we require.

What is a vertex array?

First, we need to ask, what is a vertex? A vertex is a single graphical point, that is, a coordinate. This point is defined by a horizontal and vertical position. The plural of vertex is vertices. A vertex array, then, is a whole collection of vertices.

In SFML, each vertex in a vertex array also has a color and a related additional vertex (that is, a pair of coordinates) called texture coordinates. Texture coordinates are the position of the image we want to use in terms of a sprite sheet. Later, we will see how we can position graphics and choose a part of the sprite sheet to display at each position, all with a single vertex array.

The SFML VertexArray class can hold different types of vertex sets. But each VertexArray should only hold one type of set. We use the type of set that suits the occasion.

Common scenarios in video games include, but are not limited to, the following primitive types:

  • Point: A single vertex per point.
  • Line: Two vertices per set that define the start and endpoint of the line.
  • Triangle: Three vertices per point. This is the most commonly used (in the thousands) for complex 3D models, or in pairs to create a simple rectangle such as a sprite.
  • Quad: Four vertices per set. This is a convenient way to map rectangular areas from a sprite sheet.

We will use quads in this project.

Building a background from tiles

The Zombie Arena background will be made up of a random arrangement of square images. You can think of this arrangement like tiles on a floor.

In this project, we will be using vertex arrays with quad sets. Each vertex will be part of a set of four (that is, a quad). Each vertex will define one corner of a tile from our background, while each texture coordinate will hold an appropriate value based on a specific image from the sprite sheet.

Let's look at some code to get us started. This isn't the exact code we will use in the project, but it is close and allows us to study vertex arrays before we move on to the actual implementation we will use.

Building a vertex array

As we do when we create an instance of a class, we declare our new object. The following code declares a new object of the VertexArray type, called background:

// Create a vertex array

VertexArray background;

We want to let our instance of VertexArray know which type of primitive we will be using. Remember that points, lines, triangles, and quads all have a different number of vertices. By setting the VertexArray instance to hold a specific type, it will be possible to know the start of each primitive. In our case, we want quads. Here is the code that will do this:

// What primitive type are we using

background.setPrimitiveType(Quads);

As with regular C++ arrays, a VertexArray instance needs to be set to a particular size. The VertexArray class is more flexible than a regular array, however. It allows us to change its size while the game is running. The size could be configured at the same time as the declaration, but our background needs to expand with each wave. The VertexArray class provides this functionality with the resize function. Here is the code that would set the size of our arena to a 10 by 10 tile size:

// Set the size of the vertex array

background.resize(10 * 10 * 4);

In the previous line of code, the first 10 is the width, the second 10 is the height, and 4 is the number of vertices in a quad. We could have just passed in 400, but showing the calculation like this makes it clear what we are doing. When we code the project for real, we will go a step further to aid clarity and declare variables for each part of the calculation.

We now have a VertexArray instance ready to have its hundreds of vertices configured. Here is how we set the position coordinates on the first four vertices (that is, the first quad):

// Position each vertex in the current quad

background[0].position = Vector2f(0, 0);

background[1].position = Vector2f(49, 0);

background[2].position = Vector2f(49,49);

background[3].position = Vector2f(0, 49);

Here is how we set the texture coordinates of these same vertices to the first image in the sprite sheet. These coordinates in the image file are from 0,0 (in the top-left corner) to 49,49 (in the bottom-right corner):

// Set the texture coordinates of each vertex

background[0].texCoords = Vector2f(0, 0);

background[1].texCoords = Vector2f(49, 0);

background[2].texCoords = Vector2f(49, 49);

background[3].texCoords = Vector2f(0, 49);

If we wanted to set the texture coordinates to the second image in the sprite sheet, we would have written the code like this:

// Set the texture coordinates of each vertex

background[0].texCoords = Vector2f(0, 50);

background[1].texCoords = Vector2f(49, 50);

background[2].texCoords = Vector2f(49, 99);

background[3].texCoords = Vector2f(0, 99);

Of course, if we define each and every vertex like this individually, then we are going to be spending a long time configuring even a simple 10 by 10 arena.

When we implement our background for real, we will devise a set of nested for loops that loop through each quad, pick a random background image, and assign the appropriate texture coordinates.

The code will need to be quite smart. It will need to know when it is an edge tile so that it can use the wall image from the sprite sheet. It will also need to use appropriate variables that know the position of each background tile in the sprite sheet, as well as the overall size of the required arena.

We will make this complexity manageable by putting all the code in both a separate function and a separate file. We will make the VertexArray instance usable in main by using a C++ reference.

We will examine these details later. You may have noticed that at no point have we associated a texture (the sprite sheet with the vertex array). Let's see how to do that now.

Using the vertex array to draw

We can load the sprite sheet as a texture in the same way that we load any other texture, as shown in the following code:

// Load the texture for our background vertex array

Texture textureBackground;

textureBackground.loadFromFile("graphics/background_sheet.png");

We can then draw the entire VertexArray with one call to draw:

// Draw the background

window.draw(background, &textureBackground);

The previous code is much more efficient than drawing every tile as an individual sprite.

Important note

Before we move on, notice the slightly odd-looking & notation before the textureBackground code. Your immediate thought might be that this has something to do with references. What is going on here is we are passing the address of the Texture instance instead of the actual Texture instance. We will learn more about this in the next chapter.

We are now able to use our knowledge of references and vertex arrays to implement the next stage of the Zombie Arena project.

Creating a randomly generated scrolling background

In this section, we will create a function that makes a background in a separate file. We will ensure the background will be available (in scope) to the main function by using a vertex array reference.

As we will be writing other functions that share data with the main function, we will write them all in their own .cpp files. We will provide prototypes for these functions in a new header file that we will include (with an #include directive) in ZombieArena.cpp.

To achieve this, let's make a new header file called ZombieArena.h. We are now ready to code the header file for our new function.

In this new ZombieArena.h header file, add the following highlighted code, including the function prototype:

#pragma once

using namespace sf;

int createBackground(VertexArray& rVA, IntRect arena);

The previous code allows us to write the definition of a function called createBackground. To match the prototype, the function definition must return an int value, and receive a VertexArray reference and an IntRect object as parameters.

Now, we can create a new .cpp file in which we will code the function definition. Create a new file called CreateBackground.cpp. We are now ready to code the function definition that will create our background.

Add the following code to the CreateBackground.cpp file, and then we will review it:

#include "ZombieArena.h"

int createBackground(VertexArray& rVA, IntRect arena)

{

    // Anything we do to rVA we are really doing

    // to background (in the main function)

    

    // How big is each tile/texture

    const int TILE_SIZE = 50;

    const int TILE_TYPES = 3;

    const int VERTS_IN_QUAD = 4;

    int worldWidth = arena.width / TILE_SIZE;

    int worldHeight = arena.height / TILE_SIZE;

    // What type of primitive are we using?

    rVA.setPrimitiveType(Quads);

    // Set the size of the vertex array

    rVA.resize(worldWidth * worldHeight * VERTS_IN_QUAD);

    // Start at the beginning of the vertex array

    int currentVertex = 0;

    return TILE_SIZE;

}

In the previous code, we write the function signature as well as the opening and closing curly brackets that mark the function body.

Within the function body, we declare and initialize three new int constants to hold values that we will need to refer to throughout the rest of the function. They are TILE_SIZE, TILE_TYPES, and VERTS_IN_QUAD.

The TILE_SIZE constant refers to the size in pixels of each tile within the sprite sheet. The TILE_TYPES constant refers to the number of different tiles within the sprite sheet. We could add more tiles into our sprite sheet and change TILE_TYPES to match the change, and the code we are about to write would still work. VERTS_IN_QUAD refers to the fact that there are four vertices in every quad. It is less error-prone to use this constant compared to always typing the number 4, which is less clear.

We then declare and initialize two int variables: worldWidth and worldHeight. These variables might appear obvious as to their use. They are betrayed by their names, but it is worth pointing out that they refer to the width and height of the world in the number of tiles, not pixels. The worldWidth and worldHeight variables are initialized by dividing the height and width of the passed-in arena by the TILE_SIZE constant.

Next, we get to use our reference for the first time. Remember that anything we do to rVA, we are really doing to the variable that was passed in, which is in scope in the main function (or will be when we code it).

Then, we prepare the vertex array to use quads using rVA.setType and then we make it just the right size by calling rVA.resize. To the resize function, we pass in the result of worldWidth * worldHeight * VERTS_IN_QUAD, which equates to exactly the number of vertices that our vertex array will have when we are done preparing it.

The last line of code declares and initializes currentVertex to zero. We will use currentVertex as we loop through the vertex array, initializing all the vertices.

We can now write the first part of a nested for loop that will prepare the vertex array. Add the following highlighted code and, based on what we have learned about vertex arrays, try and work out what it does:

    // Start at the beginning of the vertex array

    int currentVertex = 0;

    for (int w = 0; w < worldWidth; w++)

    {

        for (int h = 0; h < worldHeight; h++)

        {

            // Position each vertex in the current quad

            rVA[currentVertex + 0].position =

                Vector2f(w * TILE_SIZE, h * TILE_SIZE);

                

            rVA[currentVertex + 1].position =

                Vector2f((w * TILE_SIZE) + TILE_SIZE, h * TILE_SIZE);

                

            rVA[currentVertex + 2].position =

                Vector2f((w * TILE_SIZE) + TILE_SIZE, (h * TILE_SIZE)

                + TILE_SIZE);

                

            rVA[currentVertex + 3].position =

                Vector2f((w * TILE_SIZE), (h * TILE_SIZE)

                + TILE_SIZE);

                

            

            // Position ready for the next four vertices

            currentVertex = currentVertex + VERTS_IN_QUAD;

        }

    }

    return TILE_SIZE;

}

The code that we just added steps through the vertex array by using a nested for loop, which first steps through the first four vertices: currentVertex + 1, currentVertex + 2, and so on.

We access each vertex in the array using the array notation, rvA[currentVertex + 0].., and so on. Using the array notation, we call the position function, rvA[currentVertex + 0].position....

To the position function, we pass the horizontal and vertical coordinates of each vertex. We can work these coordinates out programmatically by using a combination of w, h, and TILE_SIZE.

At the end of the previous code, we position currentVertex, ready for the next pass through the nested for loop by advancing it four places (that is, adding four) with the code, that is, currentVertex = currentVertex + VERTS_IN_QUAD.

Of course, all this does is set the coordinates of our vertices; it doesn't assign a texture coordinate from the sprite sheet. This is what we will do next.

To make it absolutely clear where the new code goes, I have shown it in context, along with all the code that we wrote a moment ago. Add and study the following highlighted code:

for (int w = 0; w < worldWidth; w++)

    {

        for (int h = 0; h < worldHeight; h++)

        {

            // Position each vertex in the current quad

            rVA[currentVertex + 0].position =

                Vector2f(w * TILE_SIZE, h * TILE_SIZE);

                

            rVA[currentVertex + 1].position =

                Vector2f((w * TILE_SIZE) + TILE_SIZE, h * TILE_SIZE);

                

            rVA[currentVertex + 2].position =

                Vector2f((w * TILE_SIZE) + TILE_SIZE, (h * TILE_SIZE)

                + TILE_SIZE);

                

            rVA[currentVertex + 3].position =

                Vector2f((w * TILE_SIZE), (h * TILE_SIZE)

                + TILE_SIZE);

                

            

            // Define the position in the Texture for current quad

            // Either grass, stone, bush or wall

            if (h == 0 || h == worldHeight-1 ||

                w == 0 || w == worldWidth-1)

            {

                // Use the wall texture

                rVA[currentVertex + 0].texCoords =

                    Vector2f(0, 0 + TILE_TYPES * TILE_SIZE);

                    

                rVA[currentVertex + 1].texCoords =

                    Vector2f(TILE_SIZE, 0 +

                    TILE_TYPES * TILE_SIZE);

                    

                rVA[currentVertex + 2].texCoords =

                    Vector2f(TILE_SIZE, TILE_SIZE +

                    TILE_TYPES * TILE_SIZE);

                    

                rVA[currentVertex + 3].texCoords =

                    Vector2f(0, TILE_SIZE +

                    TILE_TYPES * TILE_SIZE);

            }

            

            // Position ready for the next for vertices

            currentVertex = currentVertex + VERTS_IN_QUAD;

        }

    }

    return TILE_SIZE;

}

The preceding highlighted code sets up the coordinates within the sprite sheet that each vertex is related to. Notice the somewhat long if condition. The condition checks whether the current quad is either one of the very first or the very last quads in the arena. If it is (one of the first or last), then this means it is part of the boundary. We can then use a simple formula using TILE_SIZE and TILE_TYPES to target the wall texture from the sprite sheet.

The array notation and the texCoords member are initialized for each vertex, in turn, to assign the appropriate corner of the wall texture within the sprite sheet.

The following code is wrapped in an else block. This means that it will run through the nested for loop each time the quad does not represent a border/wall tile. Add the following highlighted code among the existing code, and then we will examine it:

            // Define position in Texture for current quad

            // Either grass, stone, bush or wall

            if (h == 0 || h == worldHeight-1 ||

                w == 0 || w == worldWidth-1)

            {

                // Use the wall texture

                rVA[currentVertex + 0].texCoords =

                    Vector2f(0, 0 + TILE_TYPES * TILE_SIZE);

                    

                rVA[currentVertex + 1].texCoords =

                    Vector2f(TILE_SIZE, 0 +

                    TILE_TYPES * TILE_SIZE);

                    

                rVA[currentVertex + 2].texCoords =

                    Vector2f(TILE_SIZE, TILE_SIZE +

                    TILE_TYPES * TILE_SIZE);

                    

                rVA[currentVertex + 3].texCoords =

                    Vector2f(0, TILE_SIZE +

                    TILE_TYPES * TILE_SIZE);

            }

            else

            {

                // Use a random floor texture

                srand((int)time(0) + h * w - h);

                int mOrG = (rand() % TILE_TYPES);

                int verticalOffset = mOrG * TILE_SIZE;

                rVA[currentVertex + 0].texCoords =

                    Vector2f(0, 0 + verticalOffset);

                    

                rVA[currentVertex + 1].texCoords =

                    Vector2f(TILE_SIZE, 0 + verticalOffset);

                    

                rVA[currentVertex + 2].texCoords =

                    Vector2f(TILE_SIZE, TILE_SIZE + verticalOffset);

                    

                rVA[currentVertex + 3].texCoords =

                    Vector2f(0, TILE_SIZE + verticalOffset);

            }            

            // Position ready for the next for vertices

            currentVertex = currentVertex + VERTS_IN_QUAD;

        }

    }

    return TILE_SIZE;

}

The preceding highlighted code starts by seeding the random number generator with a formula that will be different in each pass through the loop. Then, the mOrG variable is initialized with a number between 0 and TILE_TYPES. This is just what we need to pick one of the tile types randomly.

Important note

mOrG stands for "mud or grass". The name is arbitrary.

Now, we declare and initialize a variable called verticalOffset by multiplying mOrG by TileSize. We now have a vertical reference point within the sprite sheet to the starting height of the randomly chosen texture for the current quad.

Now, we use a simple formula involving TILE_SIZE and verticalOffset to assign the precise coordinates of each corner of the texture to the appropriate vertex.

We can now put our new function to work in the game engine.

Using the background

We have done the tricky stuff, so this will be simple. There are three steps, as follows:

  1. Create a VertexArray.
  2. Initialize it after leveling up each wave.
  3. Draw it in each frame.

Add the following highlighted code to declare a VertexArray instance called background and load the background_sheet.png file as a texture:

// Create an instance of the Player class

Player player;

// The boundaries of the arena

IntRect arena;

// Create the background

VertexArray background;

// Load the texture for our background vertex array

Texture textureBackground;

textureBackground.loadFromFile("graphics/background_sheet.png");

// The main game loop

while (window.isOpen())

Add the following code to call the createBackground function, passing in background as a reference and arena by value. Notice that, in the highlighted code, we have also modified the way that we initialize the tileSize variable. Add the highlighted code exactly as shown:

if (state == State::PLAYING)

{

    // Prepare the level

    // We will modify the next two lines later

    arena.width = 500;

    arena.height = 500;

    arena.left = 0;

    arena.top = 0;

    // Pass the vertex array by reference

    // to the createBackground function

    int tileSize = createBackground(background, arena);

    // We will modify this line of code later

    // int tileSize = 50;

    // Spawn the player in the middle of the arena

    player.spawn(arena, resolution, tileSize);

    // Reset the clock so there isn't a frame jump

    clock.restart();

}

Note that we have replaced the int tileSize = 50 line of code because we get the value directly from the return value of the createBackground function.

Tip

For the sake of future code clarity, you should delete the int tileSize = 50 line of code and its related comment. I just commented it out to give the new code a clearer context.

Finally, it is time to do the drawing. This is really simple. All we do is call window.draw and pass the VertexArray instance, along with the textureBackground texture:

/*

 **************

 Draw the scene

 **************

 */

if (state == State::PLAYING)

{

    window.clear();

    // Set the mainView to be displayed in the window

    // And draw everything related to it

    window.setView(mainView);

    // Draw the background

    window.draw(background, &textureBackground);

    // Draw the player

    window.draw(player.getSprite());

}

Tip

If you are wondering what is going on with the odd-looking & sign in front of textureBackground, then all will be made clear in the next chapter.

You can now run the game. You will see the following output:

Here, note how the player sprite glides and rotates smoothly within the arena's confines. Although the current code in the main function draws a small arena, the CreateBackground function can create an arena of any size. We will see arenas bigger than the screen in Chapter 13, Sound Effects, File I/O, and Finishing the Game.

Summary

In this chapter, we discovered C++ references, which are special variables that act as an alias to another variable. When we pass a variable by reference instead of by value, then anything we do on the reference happens to the variable back in the calling function.

We also learned about vertex arrays and created a vertex array full of quads to draw the tiles from a sprite sheet as a background.

The elephant in the room, of course, is that our zombie game doesn't have any zombies. We'll fix that in the next chapter by learning about C++ pointers and the Standard Template Library (STL).

FAQ

Here are some questions that might be on your mind:

Q) Can you summarize these references again?

A) You must initialize a reference immediately, and it cannot be changed to reference another variable. Use references with functions so you are not working on a copy. This is good for efficiency because it avoids making copies and helps us abstract our code into functions more easily.

Q) Is there an easy way to remember the main benefit of using references?

A) To help you remember what a reference is used for, consider this short rhyme:

        Moving large objects can make our games choppy,

        passing by reference is faster than copy.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.188.238