Because I chose an authentic look to the game, the game pieces do not animate and they do not require physics.  However, the dice use physics.  This allows me to do some work with UE4 that involves probability and physics… and lots of fun 🙂

When a die is done rolling, the result must be detected based on the rotation.  To double-check that I got this part correct, I wrote some code to help me visualize all possible results in terms of (pitch, yaw, roll).  I made a grid of dice with [pitch, yaw, roll] = [0, 90, 180, 270].  That’s 4 * 4 * 4 = 64 dice.  Next I made each die in the grid rotate such that the rotation does not affect the result.  For example, 2’s (pitch, yaw, roll) is (90, 0 to 360, 0 to 360) (when pitch is 90, yaw and roll are in gimbal lock).

Dice rolling happens on the actual game board, so dice can bounce off game pieces (but game pieces are not knocked over by dice).  To keep dice from falling off the board’s edges, I added invisible walls.  To keep dice from falling through the board, I enabled CCD (continuous collision detection).  Dice can land anywhere (eg on top of each other, on top of game pieces) as long as they land flat.  If a die lands at a non-orthogonal angle (no result detected), then the die bounces until a result is detected.

For the die mesh, I use a cube collision mesh with the origin in the center.  A cube has 24 rotational symmetries, 9 planes of symmetry, and 15 reflection symmetries.  Rounded corners still allow uniformly random results as long as they are rounded the same (ie maintain the symmetries).

To randomize the dice, I randomize initial state – height, rotation, impulse, torque.  For the initial rotation, uniformly sampling each of three Euler angles (pitch, yaw, roll) with a uniform distribution of 0 to 360 degrees does not result in a uniformly distributed rotation – aka a uniform sampling of SO(3).  There exist algorithms to achieve uniform random rotation in SO(3).  A simpler method for dice is to pick from a small number of initial rotations such that the physics engine will give uniformly random results.

To achieve this, I use 6 possible numbers on top * 4 right-angle rotations = 24 possible initial rotations.  This gives us a uniformly random initial state, so anything we do (or use the physics engine to do) after that will be uniformly random as long as it’s changes to dice rotation are independent of this initial uniformly random state.  To add realism and variation, I then do another non-uniform random rotation.  Dice in the grid are spaced by cube diagonal length plus a small offset.

For the initial state, dice are grouped together in a 3D grid (1x1x1, 2x2x2, or 3x3x3).  Each die in the group has the same initial impulse (velocity).  In some cases, a die (or dice) in the group has stopped moving, but then another die can bump it.  Because of this, I do (wait for done moving) and (bouncing for non-flat dice) per group rather than per die.  Ie I wait for all dice in the group to stop moving, and if any dice land flat, then non-flat dice bounce until all dice in the group land flat.

The official game only comes with 2 movement dice and 6 combat dice.  Under normal circumstances, you would roll (2 movement dice) or (5 or less combat dice)…  The only way you’d roll more than 6 dice is if you have something like a 4 attack battle axe + 2 attack courage spell + 2 attack potion of strength.  But just for fun, I’ve included a screenshot of a movement dice pile, and a screen shot of a 200 dice roll.  I’ve also posted a video showing some die rolls in action – 2 movement dice, 3 combat dice, a 100 die stress test, and a 255 die stress test.