In this project, we will be using Unity’s new networking libraries to make a turn-based multiplayer game. I chose a very simple game, TicTacToe, so that I woudn’t be too distracted by much beyond the architecture I would need to achieve my goal. It is my first attempt to implement networking with Unity, so I am very open to feedback. If the general response is positive, then I may take it a bit further and try to make a Hearthstone sytle card game.
The completed project is available here as a git repository. You can use this to download the project in its final form, or to see how the project looked at each step of its creation – there is one commit for each lesson. Feel free to download and try out the project, or read along and create it from scratch.
Open Unity (this series was created using Unity version 5.3.1) and create a new project. There are several scripts I want to reuse from my other projects which I have provided as a unitypackage here. Download and import the package into your new project. Make sure that all assets are checked for import and click “Import”.
One of the first things I do when beginning a new project is to rough out some assets that will be needed. I lovingly call this “programmer art” because it isn’t intended to go in a finished product but does need to be there so development can continue. For this project we will need some way to represent a Tic Tac Toe board, as well as the pieces that indicate the player marks. In addition, we will add some User Interface (UI) elements.
Create an ‘X’ Mark
- Create an Empty GameObject and name it “Mark X”
- Create a cube
- Parent the cube to the “Mark X” GameObject
- Rotate the cube to rotation (Y: 45)
- Size the cube to scale (X: 0.15, Y: 0.2, Z: 0.6)
- Duplicate the cube
- Rotate the duplicate cube to rotation (Y: 315)
We’re going to need to make this into a prefab so we can easily create several instances of the mark on the board:
- Create a new Project Folder named “Prefabs”
- Drag the “Mark X” object from the Hierarchy pane onto the “Prefabs” folder in the Project pane to create a prefab from it
- Delete the “Mark X” instance from the scene
Create an ‘O’ Mark
- Create an Empty GameObject and name it “Mark O”
- Create a sphere
- Parent the sphere to the “Mark O” GameObject
- Size the sphere to scale (X: 0.6, Y: 0.3, Z: 0.6)
- Create a prefab out of “Mark O”
- Delete the “Mark O” instance from the scene
Now let’s go ahead and create the poolers which will allow us to instantiate and then reuse a collection of our marks.
- Create an empty GameObject named “X Pooler”
- Add the “Set Pooler” component to this object
- Look in the inspector at the settings for the “Set Pooler” component
- Assign the prefab field to use the “Mark X” prefab
- Tell the pooler to prepopulate with 5 instances
- Duplicate the “X Pooler”
- Rename the duplicate to “O Pooler”
- Configure the duplicate to use the “Mark O” prefab
- Reduce the duplicate’s prepoulate count to 4 instances
In this project I always let ‘X’ go first (regardless of the controlling player) which is why it gets five instances and the ‘O’ only gets four. Add them together and you have 9 marks, which is the total number I need to completely fill the Tic Tac Toe board.
Note that I skipped a few settings on the pooler because they weren’t necessary given the simplicity of this project. For example, I could have specified a “Key” for the pooler to use, but since it defaults to using the name of the prefab as its key, that was sufficient for now. Likewise I could have reduced the “Max Count” of the pooler to be the same value as the “Prepopulate” field, but I know I wont be generating more than I expect so it wasn’t necessary. I didn’t need to specify a prepopulate count either, but specifying it is more efficient than needing to resize the collection as we play.
Create the Board
- Create an empty GameObject named “Board”
- Add a Box Collider component
- Set the collider Center to (X: 1.5, Y: 0, Z: 1.5)
- Set the collider Size to (X: 3, Y: 0.1, Z: 3)
- Create a cube
- Rename the cube to “Surface”
- Parent the cube to the Board
- Move the cube to Position (X: 1.5, Y: 0, Z: 1.5)
- Size the cube to Scale (X: 3, Y: 0.1, Z: 3)
- Remove the Box Collider from the cube
If you are wondering why I created a separate container GameObject for the board with its own collider instead of just using the Cube that shows its surface, it is because I like the scale to be left at 1. Since I had to scale the cube which represents the surface of the board, any objects which are parented to it would also be scaled and the numbers are less intuitive to work with. Furthermore, with this hierarchy I could easily replace the “visual” portion of the object later with something nicer.
Now I want to give the game board a little color so that the lines and marks will stand out a little better:
- Create a new Project folder named “Materials”
- Create a new Material in that folder named “Board”
- Set the Albedo Color (R: 140, G: 163, B: 176)
- Drag the Material onto the Board’s cube surface in the scene
Next, let’s create the lines which help to visually separate the nine squares of the board:
- Create a cube
- Rename the cube to “Line”
- Parent the cube to the Board
- Move the cube to Position (X: 1, Y: 0, Z: 1.5)
- Size the cube to Scale (X: 0.02, Y: 0.11, Z: 3)
- Duplicate this line 3 times
- Move the first duplicate to Position (X: 2)
- Move the second duplicate to Position (X: 1.5, Z: 1)
- Rotate the second duplicate to Rotation (Y: 90)
- Move the third duplicate to Position (X: 1.5, Z: 2)
- Rotate the third duplicate to Rotation (Y: 90)
Let’s go ahead and keep the mark poolers as part of the Board hierarchy since they are related to it.
- Parent the “X Pooler” to the “Board”
- Parent the “Y Pooler” to the “Board”
Since we don’t need to create multiple instances of the Game Board you might think we don’t need to create a prefab out of it. In a way that’s true, as long as we save the scene we will have everything we need for this simple demo. However, I still like to create prefabs out of important objects. Especially when working on teams and using version control. By using a prefab, I will be able to make future changes to the Game Board without needing to modify the scene, and that practice allows teams to have less working conflicts among each other.
- Create a prefab out of the “Game Board” – but this time don’t delete the instance in the scene.
Now let’s position the camera so that we will have a good view of the board. I decided to leave a little perspective in there but of course that is an optional feature:
- Move the “Main Camera” to Position (X: 1.5, Y: 3, Z: -0.15)
- Rotate the “Main Camera” to Rotation (X: 60)
- In order to detect clicks or taps on the board, add a “Physics Raycaster” component to the “Main Camera” GameObject.
Create the User Interface (UI)
Our UI isn’t very demanding. All I want is three labels: one to show game state, and one for each player to indicate which mark they are controlling and how many times they have won.
- Create a Canvas
- Create a Text as a child of the Canvas
- Look in the Inspector for the “Rect Transform” component of the Text object
- Hold Alt & Shift to set the anchor and pivot preset simultaneously to “Top Center” position
- Move the Text to Position (Y: -20)
- Find the “Text” component beneath the “Rect Transform” component in the inspector
- Set the Font Size to 30
- Set the Color to White
- Add a “Content Size Fitter” component
- Set the “Horizontal Fit” and “Vertical Fit” to “Preferred Size”
- Rename this Text object to “Game State Label”
- Duplicate the Text
- Rename the duplicate to Local Player Label
- Hold Alt & Shift to set the anchor and pivot preset simultaneously to “Bottom Left” position
- Move the Text to Position (X: 10, Y: 10)
- Set the Font Size to 14
- Duplicate the “Local Player Label”
- Rename this duplicate to “Remote Player Label”
- Hold Alt & Shift to set the anchor and pivot preset simultaneously to “Bottom Right” position
- Move the Text to Position (X: -10, Y: 10)
- Set the Horizontal Text Alignment to “Right” justified
- Create a prefab from our Canvas
Before we finish we need to make sure and save both the scene and the project:
- Create a new Project folder named “Scenes”
- Save your scene in the “Scenes” folder as “Main”
- Save your project
In this lesson we prepared the project by importing some reusable code. Then we created a few simple assets which would be necessary to represent and interact with a game of TicTacToe such as the game board, the marks that are placed on it, and some UI that will help indicate what to do.
Don’t forget that if you get stuck on something, you can always check the repository for a working version here.