Chapter 7. C++ References, Sprite Sheets, and Vertex Arrays

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

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, references will help us avoid having to pass large objects between functions, which is a slow process. It is a slow process because each time we do this, a copy of the variable or object must be made.

Armed with this new knowledge about references, we will take a look at the SFML VertexArray class that allows us to build up a large image that can be very quickly and efficiently drawn to the screen using multiple images from a single image file. By the end of the chapter we will have a scaleable, random, scrolling background, using references, and a VertexArray object.

We will now talk about the following topics:

  • C++ references
  • SFML vertex arrays
  • Coding a random and 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 sent into the function where it is used.

The significance of this is two-fold:

  • If we want the function to make a permanent change to a variable, this system is no good to us.
  • When a copy is made, to pass in as an argument or return from the function, processing power and memory are consumed. For a simple int or even perhaps a sprite, this is fairly 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. An example will be useful:

int numZombies = 100; 
int& rNumZombies = numZombies; 

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

Note

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

Now we have an int called numZombies which stores the value 100 and an int reference called rNumZombies that 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, when we increment score like this:

score++; 

The score variable now stores the value 11. In addition, if we were to output rScore it would also output 11. The following 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 more about the why of references. There are two reasons to use references and we have already mentioned them. Here they are summarized again:

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

Study this code and then we can 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 funtion did this: 
   // answer = num1 + num 2; 
   // It is actually changing the value stored by a 
   return 0; 
} 
 
// Here are the two function definitions 
// They are exactly the same except that 
// the second passes a reference to a 
add(int n1, int n2, int a) 
{ 
   a = n1 + n2; 
   // a now equals 4 
   // But when the function returns a is lost forever 
} 
 
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 and the referenceAdd function takes two int variables and an int reference.

When the add function is called and the variables number1, number2, and answer are passed in, a copy of the values is made and new local variables to add (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 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 actually use a reference for something this simple. It does, however, demonstrate the mechanics of passing by reference.

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. The example using a reference to an int is a bit ambiguous because as an int is so small there is no real efficiency gain. Later in the 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 as well as their more flexible (and slightly more complicated) relations, 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.

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

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