Rolling a 3D Dice: Detect which number faces up?

I trying to get something to work in unity 3D. I have modelled a 20 sided dice and 3 want a Cheep, Stable and Reliable mechanic to detect which way up the dice is facing. I think I will detect when the objects velocity reaches zero to call the number (Unless you’d suggest a better way). But I’m honestly not even sure where to start with determining the number. I’m quite new to unity and have only completed 1 2D game.

I code in C# too.

I have many different sided dice to apply this too, so a versatile method would be very desirable.

Thank you.

If you have modeled the dice and imported it I guess you know which directions each side (number) is facing relative to the object space coordinate space. This could be solved in numerous ways. It could be done (as it sounds you like to do):

  • to find the number based on the orientation of the model
  • or, to animate the model to face a direction based on a random number draw

However, I assume based on your phrasing, that you want to do 1)

I would recommend setting up a pre-defined number of direction vectors in object space that maps to numbers in a script attached to the dice. This could be done via Inspector or hard-coded in script. For example you could use a Direction associative map for the lookup. What you can do then (as soon as you consider that the dice is no longer rolling), is to calculate which one of the direction vectors that is closest to a reference vector, e.g. world y-axis up. This would also work for non-flat surfaces as long as epsilon is set accordingly to a minimum angle. For example, let’s say this is a script attached to your dice (Psuedo right out of my head into the forum so not checked):

// Setup in Awake() or via inspector....
Dictionary<Vector3, int> lookup = new Dictionary<Vector3, int>();
lookup[Vector3.up] = 1;
lookup[Vector3.right] = 4;
// etc, will of course be a bit more complicated for a non-traditional dice
....

public int getNumber(Vector3 referenceVectorUp = Vector3.up, float epsilonDeg = 5f) {
   // here I would assert lookup is not empty, epsilon is positive and larger than smallest possible float etc

   // Transform reference up to object space
   Vector3 referenceObjectSpace = transform.InverseTransformDirection(referenceVectorUp);

   // Find smallest difference to object space direction
   float min = float.MaxValue;
   Vector3 minKey;
   foreach (Vector3 key in lookup.keySet()) {
       float a = Vector3.Angle(referenceObjectSpace, key);
       if (a <= epsilonDeg && a < min) {
          min = a;
          minKey = key;
       }
   }
   return (min < epsilonDeg) ? lookup[minKey] : -1; // -1 as error code for not within bounds
}

If you want it to be versatile I would recommend calculating the lookup table based on the mathematics behind the dice layout. Or setup the script direction vectors and epsilon differently based on each dice model.

Hope it provides some sort of help @Raxs

I think there is a much simpler way, with no complicated math.

  1. Attach an Empty to each face of the cube/die.
  2. In a script, read the Y-locations of each Empty.
  3. The Empty with the maximum Y-location is on the top face.

Of course you still need to filter to determine when the bouncing stops.

Hi currently working on this - so it might help somebody else :slight_smile:
Add box colliders to each face of your cube, a trigger to your floor and read which collider hits…

void OnTriggerStay(Collider col)
{
if (diceVelocity.x == 0f && diceVelocity.y == 0f && diceVelocity.z == 0f)
{
switch (col.gameObject.name)
{
case “Side1”:
Debug.Log("Hit side 1 " + diceNumber + “is showing”);
diceNumber = 20;
break;
case “Side2”:
Debug.Log("2 " + diceNumber + “is showing”);
diceNumber = 19;
break;
case “Side3”:
Debug.Log("3 " + diceNumber + “is showing”);
diceNumber = 18;
etc
}
147891-dicecolliders.png

…Of course this is what you do when your not a math genius :stuck_out_tongue_winking_eye:
Best!

if ( Vector3.Dot ( Vector3.up, transform.up ) > 0.9f )
The Dotproduct gives 1 if the transform aligns perfectly upwards and is 0 if the “up” direction of the dice points sideways. “transform.up” corresponds to the green arrow in local coordinates. If the dot product is bigger than 0.9 we can say that the two Vectors point pretty much in the same direction.