This project was my first entry to a game jam, GMTK 2022. The theme for this project was “roll of the dice”, and although the idea that came to me was probably likely to be recreated, I decided to run with it and polish it as much as I could.
My idea is a board of squares, which you can roll a dice over, which is fairly simple at first. To make levels more interesting, I introduced tiles that forced you to be facing a specific way in order to land on them – so that the spots on the dice match with the spots on the tile. In the later levels, a tile is introduced that adds or subtracts from one of your dice faces – but if you go over 6, it rolls over back to 1 (pun absolutely intended). The task of figuring out which way up the dice is seems difficult at first – but the solution is not to constantly track the faces of the die, but to calculate the index of its highest face(s) and then match it with its corresponding number.
The dice rolling animation is fairly simple, but because it needed to be applied to four different directions I decided to implement it procedurally rather than using Unity’s built in animator, which is notoriously difficult to use. The rotating action is achieved by slerping the dices rotation by 90 degrees. Slerping stands for spherical linear interpolation, and we use it instead of plain linear interpolation because rotations, represented by quaternions, are effectively 4D points, and if we lerped between two points we are almost guaranteed to get irregular, if not invalid rotations. Slerping is the desired behaviour – it rolls around a sphere until it reaches the desired point. After this, we can apply the position animation, which is again not just a plain lerp – we use the sine function and scale it to achieve the desired “jumping” feel. A simplified version of the algorithm is below.
float t = 0; while (t < animationTime) { t += Time.deltaTime; Vector3 pos = Vector3.Lerp(startPosition, endPosition, t / animationTime); pos.y = Mathf.Sin(t / animationTime * Mathf.PI) * 0.5f; transform.localPosition = pos; transform.localRotation = Quaternion.Lerp(startRotation, endRotation, t / animationTime); // Wait for next frame yield return null; }
I also added something to the controls to make them feel more fair. If the user presses a key just before the dice has landed, it will not move as the script has to wait for the dice animation to finish before rolling again. To fix this, I made it so that if the user presses a key a small amount of time before, the game remembers that they pressed that key, and presses it as soon as the animation has finished. Although users can’t lose as there are no enemies, it makes the controls feel more snappy and less annoying.
Finally, I added a level select and sounds. I started work on a level maker, which I may release later if I come back to the project. The sounds were quite interesting, as the dice roll sound is randomly pitched using Unity’s audio engine, but I wanted the tiles that add or subtract to play a tone (C to A) based on which face touched them. However, the tone I had only played middle C, so I had to procedurally pitch it up or down by using fixed ratios of that note to middle C (Unity uses decimals as ratios to the original pitch rather than hertz). Although it slightly annoyed me that it could never play a full scale, people still seemed to like it nonetheless.
Here were the results from the jam – from which my game got 86 ratings:

As there were 6118 entries, this puts me in the top 19.6% for creativity, 10.3% for presentation, 5.7% for enjoyment, and 8.8% overall. I am really pleased with these results, and received many more reviews than I was expecting! I’m definitely going to take part next year.

