Articles Archive
Articles Search
Director Wiki
 

Rolling Dice in 3D

April 5, 2002
by Will Turnage

Dear Handyman,

Can you advise me to how I would write a script for a random dice movement?

Thank you,

Colin


Colin,

If you want to create dice that roll randomly in a 3D world, then there's a simple way to do this. The key here is to use the Havok Physics Xtra that comes free with Director 8.5. The Havok Xtra is a physics engine that you can use with your Shockwave 3D members to create realistic movements. It's not too complicated to use, and best of all, it saves you the hassle of checking for collisions and doing some seriously complicated math.

The first step in your movie should be to create a blank Shockwave 3D cast member along with a blank Havok Physics Scene cast member. You can create both of these by selecting Insert > Media Element from within Director. In this example, you should name your Shockwave 3D world diceWorld, and name your Havok scene dicePhysics. [Editor's Note: Shockwave 3D cast members created with the Insert command have their linked property incorrectly set as TRUE.]

The next step is to create your models. If you don't want to get too complicated, then you can just create two boxes for the dice, and then another box for the table to roll the dice on. However, when you create your models, you need to include a few lines of Lingo code to make your models compatible with Havok. For the dice, which will actually move, you need to include a variation of this code for each model:

diceModel = member ("diceWorld").model ("Dice1")
diceModel.addModifier (#meshdeform)
member ("dicePhysics").makeMovableRigidBody ("Dice1", 30.0)

The first part of this code creates a reference for one of your dice. Next, you add a #meshdeform modifier to the model. The Havok Xtra needs this modifier in order to make its calculations. Finally, you make the dice a moveable, rigid body in the Havok Physics scene and you give it a mass of 30.

The floor that the dice roll on need to be fixed within the Havok scene. Otherwise, they would just succumb to the effects of gravity and plummet downward. The code to add the floor to the scene looks like this:

floorModel = member ("diceWorld").model ("Floor")
floorModel.addModifier (#meshdeform)
member ("dicePhysics").makeFixedRigidBody ("Floor")

You assign the meshdeform modifier to the model just like you did with the dice, however, with the floor you will make it a fixed rigid body in the Havok scene.

Once you have made your models in your 3D world, it is very important that you place a Havok behavior on your Shockwave 3D sprite in the Score. In this example, since you are creating the Physics from scratch, you should use the behavior entitled Havok Physics (No HKE). This behavior can be found in the Havok section of your Behavior Library palette. If you don't have these behaviors, then you can easily download them for free from Havok.

Now you're ready to write the code to roll the dice. In this example, the user will click on a button and that will start the dice rolling.

on mouseUp me

  repeat with i = 1 to 2
    diceModel = member ("dicePhysics").rigidBody ("Dice" & i)
    diceModel.position = vector (50 - (i*100), -50, 250)
    diceModel.rotation = [vector (180 - random (360), 180 - random (360), 180 - random (360) ), random (90) ]
    diceModel.linearVelocity = vector (random (100) + 100, random (100) + 100, -200)
    diceModel.applyTorque ( vector (180 - random (360), 180 - random (360), 180 - random (360)) * (random (100) + 100))
  end repeat
  timeout ("monitorDice").new (100, #checkDice, me)

end

When you click on the mouse, it sets up the physics for the dice. First it assigns one of the die models to a variable named diceModel. It is important to note, that you are not referencing the model within the Shockwave 3D cast member, but the rigid body in the Havok member. Next you assign the dice a location high above the table. Then you give the dice a completely random rotation. Next, you apply a linear velocity to the dice. You randomize the speed of the x and y axis, but you make sure that the z speed is -200, so that the dice will head straight down towards the table. Then you apply torque to the dice. This vector is also completely random and is used so that the die will spin in mid-air before it hits the table. Finally, you create a timeout object to call the checkDice handler ten times a second.

on checkDice me

  flag = true
  repeat with i = 1 to 2
    diceModel = pPhysics.rigidBody ("Dice" & i)
    if diceModel.linearVelocity.magnitude > 1 then
      flag = false
    end if
  end repeat
  if flag then
    timeout ("monitorDice").forget ()
    me.determineResults ()
  end if

end

The checkDice handler is used to check to see if the dice have stopped rolling or not. You start by setting a flag to TRUE, then test both of the dice for the magnitude of their linear velocities. If amagnitude is greater than 1, you can assume that die is still moving, so you set your flag to FALSE. If you check both dice and they have both stopped moving, then you forget the timeout object, and you determine the outcome of the roll.

on determineResults me

  diceResults = []
  repeat with i = 1 to 2
    diceModel = member ("diceWorld").model ("Dice" & i)
    diceRotation = diceModel.transform.rotation
    if abs (diceRotation.y) < 1 then
      if abs (diceRotation.x) < 1 then
        diceResults.append (2)
      else if abs (diceRotation.x + 90) < 1 then
        diceResults.append (4)
      else if abs (diceRotation.x - 90) < 1 then
        diceResults.append (3)
      else if (abs (diceRotation.x - 180) < 1) or (abs (diceRotation.x + 180) < 1) then
        diceResults.append (5)
      end if
    else
      if abs (diceRotation.y + 90 ) < 1 then
        diceResults.append (1)
      else if abs (diceRotation.y - 90 ) < 1 then
        diceResults.append (6)
      end if
    end if
  end repeat

You start this handler by creating an empty list that will contain the outcome of the roll. You repeat the same process for each die. Start by determining its exact rotation. Check to see if the y rotation of the die is between -1 and 1. If it is, then that means that the die is on its side, and there are four different possibilities for what the die could be. Then you would check the x rotation of the die to see if it is near either -180, -90, 0, 90, or 180. If you find a match, then you add a number corresponding to that rotation to your list. If the y rotation of the die is not equal to zero, then that means that the die is on its end. In this case, you check to see if the y rotation is -90 or 90, and if so, then you add 1 or 6 your list. Once you've checked the rotation of the dice, then you need to check those results to make sure the dice landed properly.

  if diceResults.count <> 2 then
    member("diceStatus").text = "The dice weren't level. Re-rolling..."
    me.mouseUp()
  else
    member("diceStatus").text = "You rolled a" && diceResults[1] && "and a" && diceResults[2]
  end if

end

You start by checking to see if there are two numbers in your list of dice results. If there are not two numbers in your list, then that means that one or both of the dice are on their side, and haven't landed squarely on one side. In this instance, you tell the user that the dice need to be re-rolled, and then you start the whole process over by calling the mouseUp handler in the same behavior. If both dice landed successfully, then you let the user know what the results of the roll was.

When you put it all together, the end result will look like this.

Click on the image to see the Shockwave movie.

A sample Director 8.5 movie is available for download in SIT or ZIP archives.

All colorized Lingo code samples have been processed by Dave Mennenoh's brilliant HTMLingo Xtra, available from his site at http://www.crackconspiracy.com/~davem/

Will Turnage is a multimedia programmer based in New York City. In addition to his weekly role as Director Online's Multimedia Handyman, he is also the Technology Director for Sony Music's Client Side Technologies Group. You can read more about his work at http://will.turnage.com/.

Copyright 1997-2024, Director Online. Article content copyright by respective authors.