5. Game #2: Robot Repair – Unity 3.x Game Development by Example

Chapter 5. Game #2: Robot Repair

One of the secret aspects of game development is that getting a mechanic working is often less challenging than getting an entire GAME working.

Our keep-up game has a working mechanic, but it's clearly nothing like a finished game.

In this chapter, we'll take a break from our keep-up game to add an important tool to our Unity game development tool belt: Graphical User Interface programming. Graphical User Interfaces, or GUIs for short, include all of the buttons, sliders, drop-downs, arrows, and on-screen text that help players understand and move through your game. Unity has a whole separate GUI (pronounced "gooey") system that we'll start digging around in to flesh out our games a bit better. To get a good grasp on what the GUI system can do, we're going to program an entire working 2D flip n' match memory game in that system!

Note

A language by any other name

Note

There's nothing particularly Unity-centric about what we're going to learn in this chapter. The techniques you learn here can generally be applied to other scripting languages to build the same game. Programming a memory game in the Unity GUI is not much different from building one in VB6, Flash, XNA, or OBJ-C for the iPhone and iPad.

In this chapter, we'll:

  • Build an entire working memory game called Robot Repair using only the Unity GUI controls

  • Learn how to add buttons and images to the screen

  • Connect multiple scenes with buttons

  • Practice our programming, including one-dimensional and two-dimensional arrays

All set? Then let's get GUI!

You'll totally flip

Let's make sure we're on the same page when I say "flip n' match memory game". That's the kind of game where you take a deck of playing cards and lay them out in a grid on the table. Then, two or more players take turns flipping over a set of two cards. If the pair of cards matches (that is, two 10s, two queens, and so on), then that player clears the matching pair from the table and gets to flip again. Otherwise, the cards are turned back face down and the next player gets a turn. The game ends when the grid is cleared. The winning player is the one who collects the most matching cards.

To start, we're going to build the basic Solitaire flip n' match game in the Unity GUI, using robots on the cards. Here's how it will look when you're finished:

There are lots of things that make flip n' match memory an ideal learning game for new developers. It's extremely versatile! The pictures on the cards can be anything you like you can skin the game in endless ways. You can build it for any number of players; a Solitaire version just needs a few extra goodies, like a timer, to make it more compelling. You can quite easily crank the difficulty up and down by tweaking the number of cards on the table, the timer length, and the types of allowable matches.

I can't wait to start! Let's go!

A blank slate

Start a new Unity project by clicking on File | New Project…. Create a new folder called robotRepair on your computer's operating system. Follow the same steps as before to choose a folder for the new project, call the project robotRepair, and click on Create. You don't need to import any extra unityPackage files if you don't want to we won't be using anything from them in this project.

When Unity has finished building your project, you should see that big, wide-open, empty 3D world. We're going to completely ignore the 3D world for this project and focus instead on the invisible 2D plane sitting in front of it. Imagine that your 3D world sits behind a sheet of glass that sheet of glass is where the Unity GUI controls exist. We'll tack up buttons and images to that sheet of glass as if they're stickers that the player can interact with.

You're making a scene

Until now, we've only been working with one Scene. Unity lets you create multiple scenes, and then daisy-chain them together. You can think of a scene as a level in your game. In our case, we're going to create a scene for the title screen of our game and another scene for the game itself.

Time for action – Setting up two scenes

The new project you just created automatically starts with a single scene. Let's rename it to title.

  1. Click on File | Save Scene As and choose title for the name of the scene. You'll notice that the title bar in Unity now says title.unity robotRepair. There's also a new scene in the Project panel called title. You can tell that it's a scene because it has a little black-and-white Unity logo next to it.

  2. Create a second scene by clicking on File | New Scene.

  3. Click on File | Save Scene As... and call this new scene game.

  4. To keep things more organized, create a folder to hold your two scenes. Click on the Create button in the Project panel and choose Folder. A new folder called New Folder appears in the Project panel.

  5. Rename the folder Scenes.

  6. Click-and-drag your game and title scenes into the Scenes folder in the Project panel. All tidy!

  7. Click on the little gray arrow to expand the Scenes folder. Double-click on the title scene to make it the active scene. You'll know that you've done it correctly if the Unity title bar says Unity title.unity robotRepair.

Now, we have a scene to hold our title screen, and a scene to hold all of our game logic. Let's get to work building that title screen!

No right answer

The more you explore Unity, the more you'll discover that there are many possible ways to do one thing. Often, there's no "right" way to do something it all depends on what you're building and how you want it to look. There can, however, be better ways to do things: as we saw earlier, programmers call these preferred methods "best practices".

You can build a title screen for your game a number of different ways. If you have a 3D world, maybe you want the camera to fly around the world as a piece of 2D title work fades up over it? Maybe the title work should be in 3D, and you start the game by moving a controllable character through a doorway? For this introduction to Unity GUI controls, we'll take a flat 2D graphic of our game title work and add a Play button on top of it. This is how it will look when we're finished:

Time for action – Preparing the GUI

In Unity, GUIs are coded in scripts, which are attached to game objects. Let's create an empty GameObject and then attach a new script to it.

  1. Click on GameObject | Create Empty. A GameObject called "GameObject" appears in the Hierarchy panel.

  2. Click on the GameObject in the Hierarchy panel and press F2. Rename it to TitleScreen.

  3. In the Inspector panel, position the TitleScreen Game Object at x:0 y:1 z:0.

  4. Right-click on a blank space in the Project panel and select Create | JavaScript.

  5. Rename the new script TitleGUI.

  6. Click-and-drag the TitleGUI script from the Project panel to the TitleScreen Game Object you just created in the Hierarchy panel. The TitleScreen Game Object should light up blue before you release the mouse button.

  7. To make sure the TitleGUI script is linked to the TitleScreen, click on the TitleScreen in the Hierarchy panel. In the Inspector panel, you should see the TitleGUI script listed beneath the Transform as one of the components of the TitleScreen.

Our script won't get executed unless it's hooked up to a Game Object. We've created an empty Game Object called TitleScreen and connected our new TitleGUI script to it. We're almost ready to start scripting!

Note

GUICam

Note

Some developers prefer to hook their GUI scripts up to the main camera in the scene. If this makes more sense to you than hooking the script up to an empty Game Object, don't let me hold you back. Go for it!

The beat of your own drum

We're going to take a few extra steps to ensure that our GUI looks different from the standard built-in Unity GUI. If you visit the Unity game portals in Chapter 1, That's One Fancy Hammer, you may notice that the buttons and UI controls in many of the games look the same or similar: dark, semi-transparent buttons with gently-rounded corners. This is because those game developers haven't bothered to give their UI controls any unique flair.

Time for action – Creating and linking a custom GUI skin

Custom styling your UI controls is definitely more work than sticking to the Unity default, but the results are worth it! If you've ever worked with Cascading Style Sheets (CSS), you'll have a better idea of what's going on here. CSS enables you to define the way a website looks, how the images are displayed, the font and size of the text, and the spacing of elements. All of the website's pages use that stylesheet to display their elements the same way. So you've got the thing, and then you've got the way the thing looks. It's like putting a costume on a kid at a birthday party. You can make the kid look like a pirate, a princess, a superhero, or a giant walking cupcake. But, the foundation of the kid doesn't change. It's still little Billy under that foam cupcake suit. Two different websites can have the exact same content, but their stylesheets could make them appear radically different.

When you custom style your UI, you create a new "costume" for it. You can apply different costumes to the GUI, but the bones stay the same. You still have the same number of buttons at the same size and in the same position on the screen. Those buttons and controls all behave the same way as they did before they're just wearing a different costume.

Let's take the first few steps towards setting up our game to use a custom UI a different costume (or "skin") for our controls.

  1. Double-click on the TitleGUI script in the Project panel to open the default script editor, MonoDevelop.

  2. At the top of the script, create a variable to hold your custom GUI skin:

    var customSkin:GUISkin;
    function Update() {
    }
    
  3. Save and close the TitleGUI script.

  4. Right-click or secondary click on any empty space in the Project panel, then click on Create | GUI Skin. You can also click on the Create button at the top of the Project panel.

  5. Rename the newly created GUI Skin MyGUI.

  6. Click on the TitleScreen Game Object in the Hierarchy panel.

  7. Look for the TitleGUI script component in the Inspector panel. Notice that the customSkin variable that we just created is now listed in the TitleGUI script component!

  8. Click-and-drag the MyGUI GUI Skin that you just created and drop it into the customSkin variable in the Inspector panel. You can also choose MyGUI from the drop-down list in that same variable field.

What just happened?

We've created a skin for our GUI, which works like a costume on a kid at a birthday party. Now, we're all set up to fiddle with the fonts, colors, and other parameters of our custom MyGUI skin. We have the costume, now we just need to describe the kid underneath it. Let's build ourselves a button, and then we'll see the difference that a custom GUI skin can make.

Time for action – Creating a button UI control

We're going to add a button to the title screen through code, using Unity's built-in OnGUI function.

  1. Double-click on the TitleGUI script, or switch over to the script editor if it's already open.

  2. We won't need the Update function any longer. Instead, we'll be using the built-in OnGUI function. Change the word Update to OnGUI:

    var customSkin:GUISkin;
    function OnGUI() {
    }
    
  3. Add a button-creating a chunk of code inside the OnGUI function:

    var customSkin:GUISkin;
    function OnGUI() {
      if(GUI.Button(Rect(0,0,100,50),"Play Game"))  {
        print("You clicked me!");
        }
    }
    
  4. Save the script and click on the Unity Play button to test your game.

A button labeled Play Game appears at the top-left of the screen. When you click on it, the message You clicked me! appears in the status bar at the bottom of the Unity interface. It will also appear in the console window if you have it open.

Great! With a very tiny bit of code, we have a working, labeled button up on the screen! It lights up when you roll over it. It goes back to normal when you roll off. Its appearance changes when you press and hold the mouse button on it. The text label is automatically centered inside the button. Somebody spent a bunch of time behind the scenes programming this GUI stuff to save us time. Thanks, Unity team!

Note

Where it all begins

Note

This Play Game button is a crucial element of our flip n' match memory game, and every game you'll ever build with Unity, or any other game-building tool for that matter! Its part of the understood language of the video game medium that games start in a paused state on a title screen and the player takes an action to start the game. In a coin-operated arcade setup, that action is inserting a quarter. In modern console gaming, that action is pressing a button on the controller. In a web game like ours, that action is clicking on a button that says Start, Play, or Play Game.

What just happened?

If you've never programmed user interfaces before, this should all seem peachy. But, if you have done some coding, you might be looking at the lines we just wrote with a completely confused look on your face. This isn't like any interface programming that you've ever seen before.

Unity uses what's called an immediate mode GUI. The term is borrowed from graphics programming, and it requires you to program a little differently than you may be used to. Let's break it down line by line.

if(GUI.Button(Rect(0,0,100,50),"Play Game"))

Like the Update function, the OnGUI function is called repeatedly as your game runs. This line is called twice a frame once to create the button and once to see if the button has been clicked. On every frame, your entire interface is recreated from scratch based on the code in your OnGUI function.

So, if you picture this code as a split-second in time, your if statement asks whether the button that you're creating in this instant is being clicked on. It's kind of a strange thing to get used to, but it makes sense the more you use it. The if in this case is like saying "if the button was clicked".

The rest of the line is a bit easier to understand. The GUI.Button method needs two arguments a rectangle defining the top-left corner and size of the button, and a label for the button.

if(GUI.Button(Rect(0,0,100,50),"Play Game"))

Rect takes four inputs: x position, y position, width, and height. The origin of the two-dimensional screen is at the top-left, so a value of 0,0 places the button at the top-left of the screen. (Note that this is in opposition to the bottom-left origin we just learned about when tracking mouse movement. This is the THIRD co-ordinate system we've encountered so far!) The width and height values of 100 and 50 make the button 100 pixels wide and 50 pixels tall.

print("You clicked me!");

This line is straightforward. When the button is clicked, the message we typed is printed to the status bar and the console window's log. Remember that the status bar is the skinny 20-pixel-high gray bar at the bottom of the Unity interface. Let's check it out one more time with a big fat arrow to help us out:

print is another way to throw messages to the Console window or the status bar. I prefer it to Debug.Log() because it's faster and easier to type, but be aware that it won't work in all situations. If you ever find yourself tearing your hair out because your print() statements aren't working, try switching to Debug.Log().

Have a go hero No sense sitting around on your button

Why stop there? To fully appreciate what this code is doing, try this:

  • Change the button label, the button position, and the button width and height.

  • Change the message that gets printed when you click on the button.

  • Try taking the button creation code out of the if statement. What happens?

Fiddling with this code is a sure-fire way to better understand it.

Want font?

As promised, we're going to try overriding the default look of the UI button control using our custom GUI skin (or "cupcake costume"). At the top of the OnGUI function, between the curly brackets, add this line:

GUI.skin = customSkin;

Save the script. Now, the custom GUI skin called MyGUI that we linked to this script will knock out the default skin like putting on a different costume. Let's make a quick change to MyGUI so that we can see the results.

Click on MyGUI in the Project panel. Now, check out the Inspector panel. There's a loooong list of goodies and controls that we can customize. This is why many of the Unity projects that you see use the default GUI customizing all this stuff would take a long time!

Click on the arrow next to Button to expand it, and then click on the arrow next to Normal. There's a color swatch here labeled Text Color (it has an eye dropper icon next to it). Click on the swatch and choose a new color I chose light blue. Click on the Play button to test your game.

Voila! The text color on your button is blue! When you roll over the button, though, the text reverts to white. There are separate colors and graphics for the hover, normal, and pressed states of the button. Yikes! That's tedious.

To change the font on your buttons, navigate to a directory on your computer where you keep your fonts, and click-and-drag the font file into the Project panel. Now, you can choose that font from the drop-down list labeled Font in the Inspector panel of your MyGUI skin.

Note

Where my fonts are?

Note

If you're running Windows, your fonts are likely to be in the C:\Windows\Fonts directory. If you're a Mac user, you should look in the /Library/Fonts/ folder.

You could spend hours messing around with your custom GUI skin. Don't let me hold you back! If you want to go nuts customizing MyGUI, be my guest. When you're ready to come back, we'll build out the rest of the title screen.

Cover your assets

Download the Assets package for this chapter (look for instructions in the Preface of this book). To import the package, click on Assets | Import Package | Custom Package. Navigate to wherever you saved the package and double-click to open it an Importing Package dialog will open. All assets should be checked by default, so click on the Import button to pull them into your Assets folder.

Open the Resources folder in the Project panel. All of the graphics that we need to build the game are now in there, including the title screen graphic it's the one called title. Click on it. You should see a preview of the Robot Repair title screen in the Inspector panel.

With the title screen graphic selected, click on GameObject | Create Other | GUI Texture. Unity analyzes the width and height of our graphic and sets it up as the background to our GUI. Click on the Play button to test your game you should now see the Play Game GUI button superimposed over the Robot Repair title screen graphic (or floating off from the top-left corner of the image, depending on your screen resolution).

Note

Don't forget to select the image

Note

Unity does a few extra steps for us when we create a GUI Texture with an image selected. If you try to create a GUI Texture and the image is not selected, you'll have to manually hook up the image and set a few parameters for it. Why bother? Make sure that the Robot Repair image is selected first and you'll save a bit of time.

Note

Beautify the background

Note

Depending on your screen resolution, you may see the default blue background color around the edges of the title screen GUI Texture. To change this color, click on the Main Camera in the Hierarchy panel. Click on the color swatch labeled Background in the Inspector panel. Change the color to white it looks the best.

Time for action – Nix the mip-mapping

There's an unwanted sparkly effect that can occur when a 3D camera gets closer and farther away from a 2D image. A technique called mip-mapping reduces this effect. Unity creates a series of images from your texture that are each half the size of the previous image, which allow the computer to figure out the best pixel colors to show to the player, reducing the sparkle effect.

Because our title screen is presented as is with no 3D camera movement, we're not really concerned about sparkle. And, as you can imagine, with all those extra images, mip-mapping adds a decent amount of processor "overhead" to our game the amount of work the computer has to do to run it. As we don't need mip-mapping adding that extra strain, let's disable it.

  1. With the title texture image selected, find the Generate Mip Maps checkbox in the Inspector panel.

  2. Uncheck the box.

  3. Click on Apply to save these changes.

  4. The rest of the images that you imported should be un-mipmapped, but there's no harm in checking them for peace of mind.

Front and center

Our title screen is almost complete, but a glaring problem is that the Play Game button is in a really goofy place, at the top-left of the screen. Let's change the code so that the button is centered on the screen and sits just beneath the title work.

Time for action – Centering the button

In order to center the button on the screen, you need to adjust the TitleGUI script.

  1. Double-click on the TitleGUI script in the Project panel, or switch over to the script editor if it's already open.

  2. Write a few new variables at the top of the script:

    // button width:
    var buttonW:int = 100; 
     // button height: 
    var buttonH:int = 50; 
       
    // half of the Screen width:
     var halfScreenW:float = Screen.width/2; 
     // half of the button width:
    var halfButtonW:float = buttonW/2; 
    
  3. Modify the button creation line in the OnGUI function to incorporate these new variables:

    if(GUI.Button(Rect(halfScreenW-halfButtonW,560,buttonW,buttonH), "Play Game");
    

What just happened investigating the code

The code is just a touch hairier now, but those variable declarations help to clarify it. First, we're storing the width and height of the button that we're going to create:

// button width
var buttonW:int = 100; 
 // button height
var buttonH:int = 50; 

Next, we're storing the value of half the screen width, which we get by dividing the Screen.width property by 2. Screen refers to what Unity calls Screen Space, which is the resolution of the published player the box or window through which the player experiences your game. By referring to Screen Space, we can center things on the screen regardless of the resolution our gamer's computer is running.

 
  // half of the Screen width
var halfScreenW:float = Screen.width/2; 

Below that, we're storing half of the button width by dividing our earlier stored value, button, by 2:

// Half of the button width
var halfButtonW:float = utton/2; 

We're storing all of these values so that we can clarify the button creation line, which looks like this:

if(GUI.Button(Rect(halfScreenW-halfButtonW,560,buttonW utton,buttonH utton), 
     "Play Game"))

Note that if we didn't store these values ahead of time, the button creation line could have been written as:

if(GUI.Button(Rect((Screen.width/2)-(100/2),560,100,50),"Play Game"))

There are a few too many brackets and mysterious numbers in there for my liking! The line where we use variable names is a lot clearer to read.

Note

Math will divide us

Computers are faster at multiplication than they are at division. If you are a stickler for speed, you can amp up this code by multiplying the values by 0.5 instead of dividing them by 2.

Note

By declaring and defining these variables at the top of the script, any of our script's functions can refer to them. They'll also show up in the Inspector panel, where we can fiddle with their values without having to open a script editor.

So, what we're doing here is putting the button halfway across the screen. Because the button builds out from its top-left corner, we're bumping it back by half its own width to make sure it's perfectly centered. The only other thing we're doing here is placing the button at 560 pixels down the screen along the Y-axis. This puts the button just beneath the title work.

Here's what your complete code should look like:

var customSkin:GUISkin;
  var buttonW:int = 100;
  var buttonH:int = 50;
  var halfScreenW:float = Screen.width/2;
  var halfButtonW:float = buttonW/2;

function OnGUI () {
  GUI.skin = customSkin;
 if(GUI.Button(Rect(halfScreenW-halfButtonW,560,buttonW,buttonH),       "Play"))
  {
    print("You clicked me!");
  }
}

Save your code and try out your game with Maximize on Play selected. It's starting to look pretty good!

To the game!

The title screen is built and the button's in place. The only thing left to do is to link the Play Game button up to take us to the "game" scene.

Modify the line inside the button call where you're printing You clicked me!. Wipe out the whole line (or comment it out using double-slashes if you want to save it for later) and type this line:

Application.LoadLevel("game");

The Application.LoadLevel call moves us from this scene to whichever scene we pass as an argument. We're passing the name of our game scene, so that's where we'll end up when we click on the button.

Time for action – Adding both scenes to the Build List

There's just one last thing we need to do. Unity keeps a laundry list of scenes to bundle together when we run the game called the Build List. If we call a scene that is not on the Build List, Unity will throw an error and the game won't work. And we don't want that.

  1. Click on File | Build Settings...; the Build Settings panel appears.

  2. Click on the Add Current button to add the title scene to the Build Settings page.

  3. Close the Build Settings panel.

  4. Click on File | Save to save the title scene.

  5. In the Project panel, double-click on the game scene to switch to it.

  6. Follow the same process to add the game scene to the Build Settings, and then close the Build Settings window. Alternately, you can click-and-drag the game scene from the Project panel into the Build Settings panel.

  7. Click on the Play button to test the game.

Note

Order! Order!

The order in which you add scenes to the Build List matters. Scenes appear from the top down. If you put your title scene at the bottom of the list, it won't appear first when you build or export your game. If you added the scenes in the wrong order, you can easily reorder them by clicking-and-dragging the scenes around in the Build Settings list.

Now that both of our scenes are on the Build List, the Application.LoadLevel call will take us to the game scene when you click on the Play Game button. When you click on the button, you should see a blank screen. That's because we haven't actually built anything in the game scene, but the button totally works! Huzzah!

Set the stage for robots

The excitement is palpable! We have a shiny-looking title screen promising something about robots. There's a glistening Play Game button that, when clicked, takes us to a new scene where our flip n' match memory game will live. It's time now to build that game.

Make sure your game's not still running the Play button at the top of the screen should not be lit up. Double-click on the game scene in the Project panel. Unity may ask you to save the title scene if you haven't already if that's the case, click on Save.

Just as we did with the title scene, we should change the camera color to white. Select the Main Camera from the Hierarchy panel, and change its view color by clicking on the color swatch in the Inspector panel.

Time for action – Preparing the game scene

We need to repeat a few steps that we followed in the title scene to set up our game scene.

  1. Go to GameObject | Create Empty and rename the new Game Object GameScreen.

  2. Create a new JavaScript file from the Project panel and name it GameScript.

  3. If you'd like to stay tidy, create a folder in the Project panel and rename it as Scripts. Drag your TitleGUI and GameScript scripts into the new Scripts folder to keep them organized.

  4. Drag-and-drop the GameScript script from the Project panel onto the GameScreen Game Object in the Hierarchy panel to link the script to a Game Object.

  5. If you feel so inclined, you can set up a customSkin variable in the script, and link up your MyGUI custom GUI skin to the script. This step is not necessary to complete the rest of this chapter.

These steps are a repeat of what we've already done on our title scene. For more detailed instructions, just thumb back a few pages!

The game plan

One of the best ways to learn game development is to build a learning project. Choose a very basic game and recreate it on your own. Many programmers use Tetris as their learning project. For a very basic introduction to a language or tool, I like to use Memory.

"But, wait!" you say: "Memory games are stupid and boring, and they're for babies, and I'll positively die if I have to build one!" Of course, you're right. You're not going to be lauded by critics and raved about by gamers by building a simple memory game. But, it's a fun challenge to set for yourself: how can you take a game that everyone has played before a million times, and put a simple twist on it to make it more interesting? How can you work within those constraints to make it your own, and to showcase your creativity?

In Robot Repair, we'll lay out a 4x4 grid of 16 cards. There are four different robot types a yellow robot, a red robot, a blue robot, and a green robot. To make things interesting, we're going to break these robots rip off an arm here, tear off a leg there. The player has to match each broken robot with its missing body part!

Once the player wins, we'll give him the option to play again. The Play Again button will link him back to the title screen.

Starting your game development career by building simple starter games like Memory is like eating a big slice of humble pie. But, this is all in the spirit of crawling before you walk. While you're crawling, how can you make things interesting for yourself? And, if you can't flex a little creative muscle in the confines of a simple game, how will you survive building your dream project?

Have some class!

To start building Robot Repair, we need to write a custom class in our GameScript script. We've already seen some built-in Unity classes in the previous chapter the Renderer class, the Input class, and so on. We're going to create our own class called Card. You guessed it the Card class is going to represent the cards in the game.

  1. Double-click to open the GameScript script.

  2. Add the following code to the script, beneath (and outside) the Update function:

    class Card extends System.Object
    {
      var isFaceUp:boolean = false;
      var isMatched:boolean = false;
      var img:String;
       
      function Card()
      {
        img = "robot";
      }
    }
    

Just like the keyword var declares a variable, we use the keyword class to declare a class. Next comes the name of our class, Card. Finally, our Card class extends System.Object, which means that it inherits all of its stuff from the built-in System.Object class…much the same way I inherited my fabulous good looks and my withered left knee that smells like almond bark.

Note

System.Object

What does it mean to inherit from System.Object? That class is like Adam/Alpha/the Big Bang it's the class from which (generally speaking) everything in Unity is derived. It's about as nondescript as anything can get. You can think of System.Object as being synonymous with "thing" or "stuff". Every single other thing we build in Unity, including our Memory game's Card class, derives from this primordial ur-thing called System.Object.

In the next few lines, we declare some variables that all cards must have. isFaceUp determines whether or not the card has been flipped. isMatched is a true or false (aka "boolean") flag that we'll set to true when the card has been matched with its partner. The img variable stores the name of the picture associated with this card.

The function called Card inside the class called Card is a special piece of code called the constructor function. The constructor is the very first function that gets called, automatically, when we create a new card. Unity knows which function is the constructor function because it has the same name as the class. The only thing that we're doing in the constructor function is setting the img variable to robot.

Great! That's all we need in our Card class for now. Let's create some important game variables off the top of the script.

Time for action – Storing the essentials

There are a few crucial values we need to remember throughout our game. Let's declare some variables at the very top of the GameScript (remember that typing the comments is optional, but the comments may help you understand the code).

var cols:int = 4; // the number of columns in the card grid
var rows:int = 4; // the number of rows in the card grid
var totalCards:int = 16;
var matchesNeededToWin:int = totalCards * 0.5; // If there are 16 cards, the player needs to find 8 matches to clear the board
var matchesMade:int = 0; // At the outset, the player has not made any matches
var cardW:int = 100; // Each card's width and height is 100 pixels
var cardH:int = 100;
var aCards:Array; // We'll store all the cards we create in this Array
var aGrid:Array; // This array will keep track of the shuffled, dealt cards
var aCardsFlipped:ArrayList; // This array will store the two cards that the player flips over
var playerCanClick:boolean; // We'll use this flag to prevent the player from clicking buttons when we don't want him to
var playerHasWon:boolean = false; // Store whether or not the player has won. This should probably start out false :)

Note

Speed kills

Remember that this line:

var matchesNeededToWin:int = totalCards * 0.5;

is exactly the same as this:

var matchesNeededToWin:int = totalCards / 2;

But, because the computer can multiply faster than it can divide, getting into the habit of multiplying could speed up your more complicated games in the future.

That's a big list of variables! Everything there should be straightforward, except what the heck is an array?

If a variable is a bucket that can hold one thing, an array is a bucket that can hold many things. We've defined some arrays to store a collection of cards, a list of cards on the table, and a list of the cards that the player has flipped over (Note that aCardsFlipped is actually an ArrayList this is because an ArrayList has a few methods that the Array class doesn't have. Using an ArrayList will speed us up later on.)

Note

"a" is for anal retentive

Programmers develop their own naming conventions for things. My own best practice when declaring arrays is to begin them with a lowercase letter "a". This is how I know, down the road, that I'm dealing with an array. It's just a code organization technique that helps me keep everything straight in my head.

Start me up

Remember that we're building this game with Unity GUI controls. Just as we created a clickable Play Game button on the title screen, we're going to build all of our clickable game cards using the same button control. Our grid of cards will be a grid of GUI buttons aligned on the screen.

Let's write a function called Start to get the ball rolling. Start is another one of those built-in Unity functions that gets called before Update or OnGUI, so it's a good place to initialize some stuff. Type this code near the top of your script, beneath the list of variables we just declared:

function Start()
{
  playerCanClick = true; // We should let the player play,         don't you 
  think?


  // Initialize the arrays as empty lists:
  aCards = new Array();
  aGrid = new Array();
  aCardsFlipped = new ArrayList();

  for(i=0; i<rows; i++)
  {
    aGrid[i] = new Array(); // Create a new, empty array at index i
      
   for(j=0; j<cols; j++)
    {
     aGrid[i][j] =  new Card();
    }
  }
}

In these first few lines, we're flagging playerCanClick to true so that the player can start playing the game right away. Then, we're using the new keyword to create new instances of the Array (or ArrayList) class, and storing them to the aCards, aGrid, and aCardsFlipped buckets.

Going loopy

What follows is a touch trickier. We want to create 16 new cards and put them into the aGrid array. To do that, we're using a nested loop to create a two-dimensional array. A 2D array is one where everything you put in the array is, itself, an array. 2D arrays are very useful when you're creating grids, like we are now.

An iterative loop is a piece of code that repeats itself, with special instructions telling it when to start and when to end. If a loop never ends, our game crashes, and we're flooded with angry tech support calls.

This line begins an iterative loop:

for(i=0; i<rows; i++)

The variable i is called the iterator. That's what we use to figure out how many times to loop, and when to stop. You don't have to use the letter i, but you'll see it a lot in other people's code. And, as we'll see shortly, when you start putting loops inside other loops, you'll actually have to start using other letters, or else your code will break.

The anatomy of a loop

An iterative loop always starts with the for keyword. It has three important sections:

  • Where to start.

  • Where to end.

  • What to do after every loop finishes.

  1. In this case, we start by setting the iterator i to zero.

    i=0
    
  2. Next, we say that we're going to loop as long as the value of i is less than (<) the value of rows. Because we've already set rows to 4, this code will loop four times.

    i<rows
    
  3. In the third section, we increase the value of i by one. Here's how the interpreter chews through our loop:

    • Set a variable called i to 0.

    • Run the code inside the loop.

    • When we're finished, increase i by one (i++).

    • Check to see if i is less than rows (4). 1 is less than 4, so let's keep going.

    • Run the code inside the loop.

    • Repeat until we increase i to 4 on the fourth loop.

    • Because i is no longer less than rows (4), stop repeating the loop.

To nest is best

The structure that we've set up is called a nested loop because we have one iterative loop running inside another. We're doing two things in our first loop stuffing a new, empty array into aGrid[i] (which means we'll eventually have an array filled with four empty arrays) and running another loop.

Inside the second loop, we're using j as the iterator because i is already in use. We're using the new keyword to create a new card, and storing it as the jth element inside aGrid[i].

Talk it through and it's not too tricky to understand:

  • The first time through the outside loop, we create a new array and add it to the aGrid array. Now, the aGrid bucket has one thing in it, at index 0: an empty array.

  • Then, we loop four times and stuff a new card into the empty array that we just created. So, aGrid is a bucket with an array inside it and that array is a list of four cards.

  • Next, we do the main loop again. We create an empty array and put it in the aGrid array. aGrid now contains an array of four cards at index 0 and an empty array at index 1.

  • On to the inner loop, we cram four new cards into the empty array that we just created. Now, aGrid contains two arrays, each with four cards inside.

  • We keep going until this whole thing plays out. At the end of the nested loop, aGrid contains four arrays, and each of those arrays has four cards in it, for a total of 16 cards.

The reason why 2D arrays are so handy is that we can easily access stuff inside them using grid co-ordinates, just like in that old board game Battleship. If we want to talk about the card two slots over and one slot down, we call it using aGrid[1][2]. In fact, if we were building a digital version of Battleship, we might use nested loops to build 2D arrays to build that game as well.

Note that arrays are zero-based. The card at aGrid[0][0] is the card at the top-left of the grid. Next to that is the card in aGrid[0][1]. Next to that is the card in aGrid[0][2]. To get the card one row down, we increase the first index: aGrid[1][2]. Here's what you should try picturing in your head:

Hopefully, you're already seeing how a grid like this relates to a grid of cards laid out on the table for a Memory game.

Seeing is believing

So far, everything we've done has been theoretical. Our cards exist in some imaginary code space, but we've done nothing to actually draw the cards to the screen. Let's build our OnGUI function and put something on the screen to see where all this is leading.

On the title screen, we used a fixed layout to position our Play Game button. We decided exactly where on the screen to put the button, and how big it should be. We're going to build our grid of cards using an Automatic Layout to illustrate the difference.

With an automatic layout, you define an area and place your GUI controls inside it. You create your controls using the built-in GUILayout class, instead of the GUI class. The controls that you create with GUILayout stretch to fill the layout area.

Time for action – Creating an area to store the grid

Let's create one of these automatic layout areas in our GameScript.

  1. We don't need the Update function in this script either. As we did earlier, change Update to OnGUI to create an OnGUI function:

    function OnGUI () {
    
  2. Begin and end the automatic layout area inside the OnGUI function:

    function OnGUI ()
    {
       GUILayout.BeginArea (Rect (0,0,Screen.width,Screen.height)); 
       GUILayout.EndArea();
    }
    

The area will be the width and height of the screen, and it will start at the screen origin at the top-left of the screen.

These two statements are like bookends or HTML tags. Any UI controls we build between these bookends will be created within the area. Each new control will automatically stack vertically beneath the last. The controls will stretch to the width of the area, which in this case is the entire screen.

Have a go hero Don't take my word for it!

If you'd like to stray off the beaten path and build a few buttons between the area statements to see what happens, I won't hold you back! Use the code we learned earlier in the chapter to create a button or two at different positions. You could also try adjusting the width, height, and start values of the area to see how that affects your UI buttons' placement.

Build that grid

Between the area statements, we want to build the grid of card buttons. But, to keep the code from getting hard to understand, we could make a function call out to a separate piece of code, just to keep things looking clean and easy to read. Modify your OnGUI code:

function OnGUI () {
   GUILayout.BeginArea (Rect (0,0,Screen.width,Screen.height));    
   BuildGrid();
   GUILayout.EndArea();
   print("building grid!");
}

That building grid! line is just there so that you can be sure something's happening. I like to add statements like these so that I can see into the mind of my computer, and to make sure certain functions are getting executed. Remember that your print statements show up in the status bar at the bottom of the screen or in the console window if you have it open.

(Note that if we actually try to run the code now, we'll get an error. Unity has no idea what the BuildGrid function is, because we haven't written it yet!)

Let's write that BuildGrid function. Add this code to the bottom of the script, outside and apart from the other chunks:

function BuildGrid()
{
 GUILayout.BeginVertical();
  for(i=0; i<rows; i++)
  {
    GUILayout.BeginHorizontal();
    for(j=0; j<cols; j++)
    {
      var card:Object = aGrid[i][j];         
      if(GUILayout.Button(Resources.Load(card.img),           GUILayout.Width(cardW)))
      {
        Debug.Log(card.img);
      }
    }
    GUILayout.EndHorizontal();   
  }
  GUILayout.EndVertical();
}

What just happened grokking the code

We start by wrapping the whole thing in vertical layout tags. Controls are stacked vertically by default within a layout area, but we're explicitly calling BeginVertical and EndVertical because of some fancy layout gymnastics that we're going to perform a few steps later.

Next, we build a nested loop. Just as before, we're looping through the columns and rows. We wrap the inner loop in a horizontal layout area with the BeginHorizontal and EndHorizontal calls. By doing this, each new card button we lay down will be stacked horizontally instead of vertically.

Finally, inside the inner loop, we're using an unfamiliar statement to create a button:

if(GUILayout.Button(Resources.Load(card.img),
     GUILayout.Width(cardW)))

In that first parameter, we're passing Resources.Load to fill the button with a picture instead of a piece of text. We pass the name of the picture we want the Resources.Load called. Because every card's img variable is set to robot, Unity pulls the picture labeled robot from the Resources folder in the Assets library and sticks it on the button.

The second parameter is a sort of an override. We don't want our card buttons stretching to fill the width of the layout area, so we pass the cardW (which is set to 100 pixels at the top of the script) to the GUILayout.Width method.

The net result is that we loop four times, and on each loop we lay down a row of four buttons, each with a picture of a robot.

Save the script and test your game. You should see a 4x4 grid of buttons, each with a yellow robot picture on it.

Now you're playing with power!

There's so much to learn about building Unity graphical user interfaces, and you've just taken the first important steps. So far, you know how to:

  • Add button UI controls to the screen

  • Tool up a custom GUI skin

  • Create new scenes, add them to the Build list, and link them together using buttons

  • Write a two-dimensional array using a nested loop

  • Lay out UI controls with both automatic and fixed positioning

As we delve deeper into our Robot Repair game, we'll learn more about automatic positioning so that we can center the game grid. We'll also figure out how to flip over cards, and add the crucial game logic to make everything function properly. Join us, won't you?