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.
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
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.
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)
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.
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?
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.
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