Scripting Dice on Roblox

Hi everyone! This is going to be a tutorial on scripting dice using Roblox Studio. Let’s start by creating the dice model.

dice
The dice model we’re going to create.

Creating the Dice Model

If you’re already comfortable using Roblox Studio to build things, you can skip this part and grab the Model off Roblox here.

  1. Create a 4×4 part.
  2. Color the dice white. Set the Top and Bottom surfaces to Smooth.
  3. Add the following decals: Top (3), Bottom (4), Front (1), Back (6), Left (2), Right (5). Credit to game-icons.net for the dice face images. Remember, opposite face values of a dice will add to 7.
  4. Add a new Script to the part, as well as a StringValue named Face and an IntValue named Roll. We’ll use these as the output for our script.
tree
The dice’s hierarchy should look like this.

Scripting the Dice

Now for the fun part. Let’s start by getting some variable references to the objects in the game hierarchy (visible in the Explorer window). Remember to open the Output window when scripting! Small note: Unless otherwise mentioned, the given code should be added from top to bottom in the script.

local dice = script.Parent
local vFace = dice.Face
local vRoll = dice.Roll

Next, let’s define a function called getHighestFace(part) which will determine the highest face of given part and return it.

local function getHighestFace(part)
	local highestFace
	local height = -math.huge
	
	-- For each NormalId (Top, Bottom, Front, Back, Left, Right)
	for k, normalId in pairs(Enum.NormalId:GetEnumItems()) do
		local y = part.CFrame:pointToWorldSpace(Vector3.FromNormalId(normalId)).y
		if y > height then
			highestFace = normalId
			height = y
		end
	end
	
	return highestFace
end

What’s going on here: We’re going over each NormalId (Top, Bottom, Left, etc). For each of these, we get a Vector3 value from the NormalId using Vector3.FromNormalId so Top translates to (0, 1, 0), Bottom is (0, -1, 0), etc. Then we’re transforming that point, which is a point local to the given part’s CFrame, into world space using pointToWorldSpace. Finally, we’re getting the Y component (height) of the resulting world point.

The rest of the this function is simply finding the face that gives the highest world point. There’s the meat of the program – now let’s hook it up into something practical by writing an update function that uses the getHighestFace function.

local function update()
	local highestFace = getHighestFace(dice)
	vFace.Value = highestFace.Name
end

This is simple enough: get the highest face of the dice, then stuff it into the Face StringValue. We’ll revisit this function later to determine what number is on what side of the dice. For now, we’ll use this line to connect the update function with the RunService‘s Stepped event, which fires about 30 times a second when the game is unpaused.

game:GetService("RunService").Stepped:connect(update)

You could also add a while-true-do loop and update on your own frequency if you wanted. Test your script by pressing play, then rotating your dice. If the Face StringValue’s Value changes accurately based on the highest face, then you’ve done got the basis of your dice! If not, check the Output window for any red error messages or yellow warnings. One little typo can mess up the entire script!

If your dice is working properly, let’s go back and update the update function so that it determines which number is on what side of the dice. Add this to the top of your script:

local faceValues = {
	Front = 1; Back = 6;
	Left = 2; Right = 5;
	Top = 3; Bottom = 4;
}

This is a table we’ll use to look up values of the dice decals that are on whatever side of the part is highest. Update your update function to this:

local function update()
	local highestFace = getHighestFace(dice)
	vFace.Value = highestFace.Name
	vRoll.Value = faceValues[vFace.Value]
end

This will stuff the current face’s value into the Roll IntValue. This way, another script in your game could read the current dice roll without having to do any math.

And that’s it! Go ahead and play around with your dice in Play mode and make sure each side corresponds to the correct value. If not, you might have to switch some values in the faceValues table. If none of your values are changing, check the Output for errors.

Here’s the completed dice model in case you got stuck or lost.

dice