Dana Vrajitoru
I310/D513 Multimedia Arts and Technology

I310 Lab 8

Date: Tuesday, October 25, 2016. Due: Tuesday, November 1, 2016.

In this lab we will explore the integration of visual and audio elements in a Unity C# project. The goal is to create a simple game of slots.

The explanations are based on a Windows installation of Unity 5.4.1f1. If you have a different version, things might work a slightly differently. You will also need Visual Studio Community edition.

Ex. 1. a. Setup

Download the zip file lab8Assets.zip from Canvas and extract the folder inside.

The folder should contain some image and audio files.

Open Unity and create a new project. In the project creation dialog, give it the name Slots and set the type as 2D. Make sure that the Default layer is selected in the top right corner of the window. Also, make sure that under Scene (top center) 2D is highlighted. From the third button to the right of 2D, toggle off the skybox and the fog.

When you work on the homework, you can experiment with other layouts and see if there is one you like better. The explanations here will be based on the default.

The are under Scene is your work area where you will build your game environment. The tab next to it, called Game, is the test area where the game is run. Below under Assets is an area where you will organize your project resources. The Inspector lets you edit the properties of your game objects. Then on the left side, the Hierarchy gives you access to all the game objects and shows their dependencies.

On the left of Assets, click on Create - Folder and name it Images. Click on it on the left to display its content (empty).

It should be displayed inside Assets now.

Open an explorer window with the folder you extracted. Select all your image files and drag them into the Images folder under Assets in Unity. Repeat the operation by creating a folder called Sounds and dragging all the mp3 files from the folder into it.

There should be 8 such images. If the project was created as 2D, each of them should have been imported as a Sprite. You can verify that this is the case by clicking on them and checking in the Inspector under Texture Type that it is Sprite (2D and UI). If it isn't, then set it that way. Normally, sprites have a little arrow on the right side on them.

From the File menu, do Save Scene As. Create a folder under Assets called Scenes and save it inside as slots.

A Unity project must have at least one scene, and can have more than one depending on the situation. The intro could be one, main menu another, play area another. You can program different levels in a game as individual scenes.

Click on the Game tab, then on the Free Aspect above the blue area and select 3:2.

This insures that your game will look the same no matter how the window is resized.

Click back the Scene tab. Drag the machine sprite from the Images onto the scene. Zoom out a little to be able to see the entire camera rectangle. Drag the corners of the sprite while holding the Shift to scale it to cover the camera area as well as you can. Click on the play button above the scene to see the result. Try resizing the window to see how it affects the look. Click on Play again to stop it when you're done.

Unity lets you modify the scene while you're playing to test things out. Remember that these changes are gone when you stop playing the scene.

Drag the sprite button1 to the scene and place it in the bottom area of the machine to the right of the word Jackpot. Make it a big bigger while holding the shift to make sure it stays a circle. In the Inspector, rename it simply button.

We will use this button to roll the slots. The second one will be used as highlight when we click on it.

Zoom in on the 3 white squares.

The scroll button zooms in and out. The right mouse button can be used to move the whole scene around.

Drag 3 of the square sprites and place them over them. You will probably need to scale them down. Scale the first of them manually, then look in the Inspector at the values of the Scale in the Transform. Round those to 2 or 3 digits, then set the same value to the Scale over X and Y for all 3 sprites.

This should set them with the same size and perfectly square.

Then set the Y coordinate in the Position area of the Transform with the same value for all 3 of them.

This way they are aligned with each other. For example, for my settings 0.82 for the scale and 2.15 for the Y position worked well. Your values could be different depending on how you scaled the machine sprite

In Inspector, name the three square sprites reelL, reelM, and reelR .

These objects will hold the random images resulting from rolling the reels. Some randomizing will happen to them and the sprite they display will also change.

Zoom out to see the whole area again.

Components can be used with game objects to add all kind of functionality to them. The button needs a component called Collider to allow detecting when the mouse is over it.

Select the button object from the Hierarchy or the Scene itself. In the Inspector clock on Add Component, Physics 2D, Circle Collider 2D.

Since the sprite itself is circular, the collider should have been created with the perfect size. You can zoom in on this object to see the green outline around it. That is the collider. If it didn't fit perfectly, we could adjust it after creation. You can zoom out a little now. Let's put it to use.

b. Script

With the button still selected, click on Add Component, New Script. At the top give it the name ButtonManager and make sure it's of type C Sharp. Then click on Create and Add. Create a folder in the Assets called Scripts and move this script there from the Assets folder (inside Unity). Then double-click on this script.

This should open Visual Studio Community and create a project for it.

Inside the class ButtonManager, all the way at the top, declare the following attribute:

public bool mouseOver;

This will be set to true when the mouse is over the button, and false when it exits. This way, when a mouse click happens, we will know if we clicked on this button or not.

In the function Start, add the line

mouseOver = false;

We cannot define constructors on classes associated with Unity objects because these objects are not created through the code. The function Start is in place of a constructor and is called when the program is launched.

Add the following functions inside the class:

void OnMouseOver()
{
    mouseOver = true;
}
void OnMouseExit()
{
    mouseOver = false;
}

These functions are called when the mouse enters or exits the area of the sprite. They need a collider to work properly.

Compile the project with Ctrl-Shift-b and then go back to Unity and run it. Click on the button object in the hierarchy, and notice the Mouse Over property in the Inspector, in the Button Manager section. Click anywhere in the game area to set the focus on it. Then move the mouse over and out of the button area, and notice the changes to the Mouse Over property.

Unity will show any public attribute of the object in the Inspector and even let you set its value or connect it to other objects from the Unity scene editor.

Let's change the sprite of the button when we click on it.

In Visual Studio, below the declaration of mouseOver, add the following variable declaration:

public Sprite spriteIdle, spriteClick;

Then go to Unity, click on the button object, and note Sprite Idle and Sprite Click being added to the ButtonManager area. Drag and drop the two button sprites from the Assets folder onto the value fields of these attributes.

This assigns to the two attributes a reference to the two Sprite objects.

Back in Visual Studio, add the following code inside the function Update:

if (Input.GetMouseButtonDown(0) && mouseOver)
{
    GetComponent<SpriteRenderer>().sprite = spriteClick;
}
else if (Input.GetMouseButtonUp(0))
{
    GetComponent<SpriteRenderer>().sprite = spriteIdle;
}

The Input functions verify whether the mouse button is down or up, respectively. The parameter value is 0 for the left button and 1 for the right button. The function GetComponent gives us access to other components of the Unity object (the button in this case) outside of the script itself.

Play the game to see the functionality at work.

Let's make it play a sound when we click on it.

In Unity, add a component to the button: from Audio - Audio Source. Drag the sound called press from the Sounds in Assets folder on the AudioClip attribute of the Audio Source component. Make sure that none of the flags of this component are checked. Then in Visual Studio, add the following line inside the block for when the button is down in the function Update:

GetComponent<AudioSource>().Play();

Run the game to check if the sound is played when we click the button.

An object in Unity can have only one Audio Source component and an AudioSource can only have one Audio Clip. However, we can play more than one sound by storing references to other audio clips in class attributes, and setting the value of the AudioClip with another sound before we play it. Let's set up this class so that we can play any of the sounds. We will start by creating an array to store these sounds.

Add the following attribute to the class ButtonManager:
public AudioClip[] sounds;

Normally, we should initialize an array with a given size using the operator new, but Unity allows us to set its size and content directly from its editor.

Go back to Unity and observe this new attribute. Increment the size to 4, then drag each sound clip from the Sounds folder to the 4 elements of this array in the order: press, tap, win, lost.

Now we want a function that receives an index as parameter, sets the Audio Clip attribute of the audio source with the sound stored in the array at that index, and then plays it.

Add the following function to the class ButtonManager:
void PlaySound(int which)
{
    if (which < 0 || which >= sounds.Length)
        return;
    GetComponent<AudioSource>().clip = sounds[which];
    GetComponent<AudioSource>().Play();
}

Then replace the entire call to the function Play with
PlaySound(0);

You can experiment with all the sound numbers to see if they play the right sound.

Let's make the reels spin when we click on the button. But first, we need to add some references to these objects in the class.

Add the following attribute to the class ButtonManager:
public GameObject[] reels;
Then set its size in Unity to 3 and drag the 3 reel objects (not the images) onto its elements from left to right.

Before we can spin the images, we need access to all the sprites that we can display on these reels.

Create an array of Sprite type called sprites. In Unity, set its size to 5 and drag all the sprites to its elements.

Spinning these reels will be done through the function Update. Since this function is called once per frame of the game, we need a function to initialize the spinning when the mouse button is up, and another one to continue spinning for a while, and eventually stop. We will use a countdown for the number of times each reel will spin.

Add the following class attributes:
int[] countDown;
bool spinning;


Then in the function Start, add the following lines:
countDown = new int[reels.Length];
spinning = false;

The starting function will initialize each countdown with a different value.

Add the following function to the class:
void StartSpin()
{
    for (int i=0; i<reels.Length; i++)
        countDown[i] = 10*(i+1);
    spinning = true;
}


Call the function inside the function Update, when the mouse button is up, after changing the sprite of the button.

Then the function that actually spins the reels has to be called from the function Update every time the variable spinning is true. For each spin, the function will choose a random sprite and assign it to the reel object.

Add the following function to the class
void SpinReels()
{
    spinning = false;
    for (int i=0; i < reels.Length; i++)
    {
        if (countDown[i] > 0)
        {
            spinning = true;
            countDown[i]--;
            int j = Random.Range(0, sprites.Length);
            reels[i].GetComponent<SpriteRenderer>().sprite = sprites[j];
            if (countDown[i] == 0)
                PlaySound(1);
        }
    }
}

Then call this function inside the function Update with a test for spinning being true.

We still need to store the values of the reels when we stop so that we can decide if the player has won or lost.

Add as class attribute an integer array called reelVal and initialize it the same way as the countDown in the function Start. Then inside the function SpinReels, assign it the random value j. Then add a function called CheckWin that checks if the values of the 3 reels are the same, and if they are, play the sound with index 2, otherwise play the one of index 3. Then go back to the function SpinReels and at the end, after the loop, check if the value of spinning is false (we've stopped spinning) and call the function CheckWin if that is the case.

We would still like to add a score that can be displayed somewhere on the page and that is updated every time the player wins something.

From the Create menu below the Hierarchy, add a UI object of type Text. In the Text area, type Score: 0. Set the size to 24, and the style to Bold. Start with 0, 0, 0 as its position. Play the game to see where it is placed (it's hard to tell otherwise), then change the position little by little to get it in the blue area below the word Jackpot. Set its color to something you think is appropriate.

We need to add a reference in the class ButtonManager to be able to change its value during game play.

At the top of the script, before the class, add the line
using UnityEngine.UI;

Then add the attribute declaration:
public Text scoreText;

In Unity, connect the Text object Score with the attribute Score Text of the button. Then declare an attribute called score in the class and initialize it as 0 in the function Start. Finally, in the function CheckWin, if the user won something, increment the score, then add the line:
scoreText.text = "Score: " + score;

Test the program to see if it works.

We still need to create an executable to be able to publish the game.

In Unity, from the File menu, choose Build Settings. Choose a PC, Mac, or Linux standalone application and click on Add Open Scene to add the scene to the executable. Then click on Build and Run. Create a folder for it called WindowsExe (or MacExe if you work on a Mac) and give the executable the name "slots". Unity will create the executable and run the program. This is the end of the lab.

Upload: Zip the entire folder created at the last step containing the executable and all the resources it needs. Add the source file ButtonManager.cs (in Assets - Scripts) that you created to the same zip file. The zip file is your lab submission. There is a second part that you will have to work on at home with your team, explained in Homework 8.