Master tactical dice battles! Enjoy the clever combination of skill and luck. Dice Hunter is a turn-based role playing game with collectible dice. Play now for FREE!
Become the Dicemancer and assume the incredible ability to capture creatures into dice. Hunt dice and wield them to save the Land of Chance from the marauding minions and evil allies of the wicked Snake Eyes. – Greener Grass, Dice Hunter: Quest of the Dicemancer Google Play Store Page
Start To Finish Video:
Part 1: Making the Dice
First off, I made the dices using Blender (which you can get on Steam now). I used the default cube that’s already on the scene upon startup. Then, I added a cylinder and duplicated it (in edit mode).
After that, I applied a Boolean modifier to the cube and set the object parameter to the cylinder that I’ve created in the previous step; Finally, I set the operation parameter to Difference. This way, Blender will ‘subtract’ the area of the cylinder that intersects with the cube and close the inside of the ‘holes’ made.
After that, you’ll notice that there were some ugly faces on the cube (in edit mode). This is because the boolean operation doesn’t take any consideration about triangles or quads. It’ll just perform the operation and connect the vertices of the main object and the ‘holes’ made during the operation.
In order to fix this, I applied another modifier to the cube – Remesh. This modifier re-solves the mesh and figure out another way of distributing the vertices of that mesh. You can see it here, after applying the remesh modifier, I came up with a cube with these vertices:
After that, in order to get rid of the sharp edges (real life dices doesn’t have those sharp edges. Well, not that I know of.), I applied another modifier – Yes, I love modifiers – to the mesh, a Subsurf modifier.
After that, you can add another modifier, a Decimate modifier, in order to reduce the number of vertices. Or, you can just reduce the number of subsurf steps. After making the cube, I exported it to a FBX file and imported it in Unity.
Part 2: Unity Setup
In Unity, I made a simple scene with a plane (for the ground) and six dices, just like in Dice Hunter.
Part 3: PROGRAMMING!!!
To start off, I added a RigidBody component to each of the die. This is because I want to make the dices react or have a realistic motion/physics. After that I made a variable referencing the RigidBody component and applied a force to the dices every time the left mouse button is pressed.
using UnityEngine; public class DiceTossScript : MonoBehaviour { private static float force = 150f; private Rigidbody rb; private void Start() { rb = GetComponent<Rigidbody>(); } private void FixedUpdate() { if (Input.GetMouseButtonDown(0)) { rb.AddForce(Vector3.up * force); } } }
The reason why I used Vector3.up instead of transform.up is because, the latter one will change when the object rotates while the former is constantly pointing to the ‘up of the world’, the global up, whatever you call it, the up of everything.
After that I added another piece of code in the FixedUpdate function which will add a torque (or rotation force, if you will) to the cube which will make it rotate randomly.
private void FixedUpdate() { if (Input.GetMouseButtonDown(0)) { //This generates a random point to apply the torque //This way, the dices will rotate randomly var temp = new Vector3(Random.Range(-1f, 1f), 0f, Random.Range(-1f, 1f)); rb.AddForce(Vector3.up * force); rb.AddTorque(temp * 1000f); } }
I also added a physics material that has a bounciness in it. Then, I set the friction to minimum in order to prevent the dices from ‘standing’ on their edges. This happens because of the friction between the edges and the ground which makes the dice fall super slowly, which does not happen in real life (well, maybe…).
Then for determining which face is up, I added triggers on each side of the die. The main logic I thought of is that, the trigger will check if it’s hitting the ground; if it does, the die will return the number of the opposite side.
After that, I wrote a script that will be applied on each of these triggers with will perform the logic stated above.
using UnityEngine; public class SideIndicator : MonoBehaviour { private void OnTriggerStay(Collider other) { if (other.transform.name == "Ground") { var parent = transform.parent.GetComponent<DiceTossScript>(); var temp = int.Parse(transform.name); DiceTossScript.combination[parent.diceIndex] = temp; } } }
I also added a static array of integers in the DiceTossScript in order to hold the combination of the faces up. Just like in Dice Hunter, this can be used in order to determine how many ‘attack’ faces are up for combos and other power ups.
After that, I also added a diceIndex on each die which corresponds to an index in the array of integers. That is, die 1 is mapped to array[0], die 2 is mapped to array[1], and so on.
//Declaration of the int array and the diceIndex variables public static int[] combination; public int diceIndex = 0; private void Start() { rb = GetComponent<Rigidbody>(); //Initialization of the array that has six elements //Each element corresponds to each dice combination = new int[6]; }
Then, I noticed that there was unnecessary rotation in the y-axis when the dices land, which does not happen in Dice Hunter. This is fixed by multiplying the angularVelocity of the RigidBody to 0, which basically stops it, when the dices are already close to their initial y-position. I did this in the update function, you can also perform this checking in the LateUpdate function, if you want to.
private void Update() { if(transform.position.y < 0.35f) rb.angularVelocity *= 0f; }
And that’s it. Moving on from here, you can use the combination array in order to build more on a game mechanics.
Here are the final codes:
For the DiceTossScript.cs:
using UnityEngine; public class DiceTossScript : MonoBehaviour { private static float force = 150f; public static int[] combination; public int diceIndex = 0; private Rigidbody rb; private void Start() { rb = GetComponent<Rigidbody>(); combination = new int[6]; } private void Update() { if(transform.position.y < 0.35f) rb.angularVelocity *= 0f; } private void FixedUpdate() { if (Input.GetMouseButtonDown(0)) { var temp = new Vector3(Random.Range(-1f, 1f), 0f, Random.Range(-1f, 1f));rb.AddForce(Vector3.up * force); rb.AddTorque(temp * 1000f); } } }
And for the SideIndicator.cs:
using UnityEngine; public class SideIndicator : MonoBehaviour { private void OnTriggerStay(Collider other) { if (other.transform.name == "Ground") { var parent = transform.parent.GetComponent<dicetossscript>(); var temp = int.Parse(transform.name); DiceTossScript.combination[parent.diceIndex] = temp; } } }
There you have it, I hope you enjoyed the tutorial. There were errors here and there and that is the beauty of learning – we make mistakes and we learn from them.
If you have comments, suggestions, recommendations, and questions, comment them down below and let’s have a healthy discussion.
Thank you and see you in the next one!