Yatzy is an online multiplayer dice game where players take turns rolling five dice to score points.
The goal of this project was to make a game that involves online multiplayer. I wanted to learn how networking works even if I could only scratch the very surface of it.
I decided to use Unity's Netcode for GameObjects as a starting point for me to learn.
DICE VALUE DEMO - if there is a green vector, then a value is found
The approach I went for is straightforward — Dot Product
First, I have empty GameObjects that are located exactly at the faces of the dice. Let's name the GameObject, DiceFace.
Then I loop through each dice face and calculate the direction of the face by doing (diceFace.transform.position - model.transform.position).normalized
Now, I can compare the direction to wherever I want to be as the top. For example, Vector3.Dot(diceFaceDirection, Vector3.up). If the dot product is within a margin like 0.95 and above then it means that specific face is facing upwards.
To get a value, I simply created a class call DiceFace that stores the dice face GameObject and an integer that resembles the face's value.
Then I would loop through a list of DiceFace and check accordingly and get the integer if the conditions are met.
This works on dice with different amount of sides. However, it will require effort when setting up the dice faces.
Code Samples
Modular class for combinations
Combination Rules Demo (Calculating scores for each rule)
Initially, I wanted to have a single scriptable object that works with different types of rules. For example, the upper section of the scoreboard is to get as many as possible while the lower section is to match specific values.
But then I decided to just use inheritance so that if needed a different type of matching, then I could just create a new child class that has a different matching function.
So now, I would have a base abstract class called CombinationRule with some essential variables like rule name, points and also a function called TryMatch that will be dependent on the child classes' implementation. Then, I create a child class called AsManyAsPossibleRule and have the TryMatch to just check if it has as many Ones for example.
Code Samples
The State Pattern
For all my projects, I would try to learn at least one new thing and integrate it to the project to widen my horizons.
In this project, I specifically chose to learn the State Pattern.
The reason why is that for my past projects, I always used a switch case in the Update loop to do a state check and there was no state entering or exiting logic that I can do within the Update loop. With the State Pattern, it helps with that and is also reusable for different state machines.
I used it to handle the state the player in the game, such as the passive state, the roll die state, etc.
Code Samples
Unity's Netcode for GameObjects
Clients connected through Unity Relay
Prior to this project, I have 0 knowledge on how to implement networking into a project.
So I had to spend some time to familiarise myself with the terminologies and concepts (e.g. RPCs, Server/Client authoritative, etc.), which took about a week or two.
I learned how to handle player connection and disconnection, how to use Relay (A tool from Unity Cloud), how to sync data using NetworkVariable, NetworkList and RPCs.
Most importantly, I had to decide how to make things synchronized. For example, how do I have the updated value on the server sync with all clients.
After having the game loop work with network code, I worked on the lobby scene that handles connection.
This is where most of the network stuff I learned are implemented. (i.e. Unity Transport, Relay, player name, player ready state)
With the help of Unity's cloud services, I didn't have to worry about port forwarding and hosting my own servers, which lifted a huge weight off my shoulders.