Trying to make dice, need some help

Hello, all! I am making a game that entails a pair of dice of which would pick a mini game, and would like to how I can make a system using variables to track the orientation of the dice so that the game knows what the dice land on and would trigger a certain mini game.

the script:

local Dice = game.Workspace.GameParts.Dice

local Gravity = math.random(200,1000)

print(Gravity)

game.Workspace.Gravity = Gravity

while true do

wait(15)

Dice.Dice1.Anchored = false – Rolls first dice

wait(.75)

Dice.Dice2.Anchored = false – Rolls second dice

wait (10)

end

other pics:

Screen Shot 2020-05-01 at 11.59.16 AM

3 Likes

In my eyes you would have to do somehting like this, Heres some quick pseudocode for you.

local minigames = game.ServerStorage:GetChildren("MiniGames") -- Or wherever your minigames are stored
local selectMap = math.random(1,#minigames)
if  selectmap == 1 then
    RollDice to show 1
elseif selectmap == 2 then
    RollDice to show 2
end
2 Likes

I tried that but it doesn’t work with the dice in-game. what I really need is a way to track which side is facing up.

(the dice are two parts with six different decals on each side)

Im not entirely sure if thats possible, Try and check ROBLOX API and see if theres a way to do this?

Maybe you can use the Orientation property of the parts to figure out how they’re rotated. Then figure out which number would be on the top of each die from its orientation.

2 Likes

Then would there be a way to make a variable that uses each of the parameters of orientation as its value?

I that were the case then i would make some if statements using those variables to fill in the empty parameters.

say… if dice1.orientation = (x,y,0)

then do that for each face of each die

1 Like

Yes. You can take the X Y and Z of the orientation and use if statements to find out which number is facing up.

A way to (possibly) get this working is to attach parts to each face of the dice (if the dice is one mesh/part/union), name them accordingly, and get the part with the highest Y position.

This is assuming that the parts are children of the dice

wait(10) -- after both dice have been rolled
local d1temp = { 0, "None" } -- first is the Y value, 0 is the minimum. Set it below 0 if your dice is on a negative coordinate. Second is the name of the part attached to the face. Example: "Face2" for the number 2 face.
local d2temp = { 0, "None" } -- array for the second dice

for i,v in pairs(Dice.Dice1:GetChildren()) do
    if v.Position.Y > d1temp[1] then -- checks if Y position is higher that the current highest
        d1temp[1] = v.Position.Y -- sets the new highest record
        d1temp[2] = v.Name -- sets the name of the part. Example: "Face2"
    end
end
-- repeat for loop, this time for second dice using the second array
local d1highestname = d1temp[2] -- gets the name value
local d1highest = tonumber(string.sub(d1highestname, 5)) -- gets the digit from the name (Example name: "Face2")
-- repeat last block of code for second dice

That might work, I haven’t tested it yet. However, it is not the best solution.

You can try attaching parts to each face of the part by welding and name each part the name that they are on. You can cast a ray above the dice towards it and you should be able to find the side it’s on:

local diceBlock = -- dice block
local start = diceBlock.Position:VectorToWorldSpace(0, 5, 0)
local ray = Ray.new(start, diceBlock.Position - start)
local hit = workspace:FindPartOnRayWithWhiteList(ray, {diceBlock}) -- so it can't intersect with other parts

print(hit)

What if it detects that it has landed when it drops?

@derpy_dog, this might be a helpful tip (Sorry if off-topic)

do three ``` to make a script in you post, then close it with another three.

like this

2 Likes

Wait for the dice to have 0 velocity and rotvelocity, then check which side is up.

Crazyman32 has already solved this for you:

3 Likes

Crazyman32’s video explains it well, but you don’t actually have to use any trig, just the dot product. Here’s a function to detect which side is facing up:

local upNormal = Vector3.new(0, 1, 0)   -- world space up vector

local function FindUpSurace(part)
	local max = -1   -- dot product can't return below 0, so -1 works fine
	local surface   -- which surface is facing up, the result
	
	for i, enum in pairs(Enum.NormalId:GetEnumItems()) do   -- go through each surface normal
	    local relativeFaceNormal = part.CFrame:VectorToWorldSpace(Vector3.FromNormalId(enum))   -- find the part's surface in world space
		local dot = upNormal:Dot(relativeFaceNormal)	-- find dot product between world up and part's surface
	    if dot > max then	-- since the biggest dot product will be the smallest angle because the magnitudes of the vectors are the most similar (try acos(0.1) vs acos(0.9) to prove this), bigger dot products are more up
	        max = dot
	        surface = enum
	    end
	end
	
	return surface   -- the result
end

After writing this, I saw @Courageous_Canister’s post and realized that they were onto something. This didn’t even cross my mind, but naturally the surface facing up would have the highest Y position in world space, so a really simple solution would be:

local function FindUpSurface(part)
	local surface
	local max_height = -math.huge

	for i, enum in pairs(Enum.NormalId:GetEnumItems()) do
		local enum_height = (part.CFrame*CFrame.new(Vector3.FromNormalId(enum))).Y   -- find the y position in world space of the part's surface
		if enum_height > max_height then   -- if it's higher than the previous ones then it's more up!
			max_height = enum_height
			surface = enum
		end
	end

	return surface
end

Either method works, the latter height method is much simpler but the former dot product method is more useful for other applications.

1 Like

is this script supposed to go into the part? because I’m using the ServerScriptStorage to contain this script. is there a way to retype it so that i can have it in the same script?

It’s a function… Use it anywhere

lol ok (sorry, I mean no offense as i am new to this)

That’s alright, just make sure you try to solve your problem before asking. Also please mark the post as the solution if it’s the solution so others who read your post later can find it quickly.

Hopefully something like this should help, make sure to read the comments to understand the code, If you have any questions, feel free to ask me. :slight_smile:

local minigames = ... -- a list of your minigames
local randomMinigames = {}
for i = 1, 6 do -- has a random minigame for each side of the die
	local minigame = minigames[Random.new():NextInteger(1, #minigames)] -- a random number selector, like math.random but more random.
	table.insert(randomMinigames, minigame)
end
local die = ... -- path to die (singular for dice)
local velocity = Random.new():NextInteger(100, 200)
die.Velocity = Vector3.new(0, velocity, 0)
repeat wait(1) until die.Velocity.Magnitude == 0 and die.RotVelocity.Magnitude == 0 -- wait until die stops
local newRay = Ray.new(die.Position, die.Position + Vector3.new(0, 100, 0))
local _, _, surface = workspace:FindPartOnRay(newRay, { die }) -- so the die is the only part that is picked, so you can get the surface of the die
print(surface) -- returns a normalid (https://developer.roblox.com/en-us/api-reference/enum/NormalId)
-- im pretty sure you can do the surfacenormal value to chose a random one
local finalMinigame = randomMinigames[surface.Value] -- the chosen minigame

So, more into this, I’m needing this to print out the number that it lands on into the output so that I can better understand how it works. This would then allow me to more easily teleport the players