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.