I’m trying to rotate a part on all axes, but it turns out to be super slow and choppy. I’m trying to achieve the dice-roll from Mario Party.
This is the code I currently have:
repeat
wait(0.05)
Timer = Timer + 0.05
local X = Die.Orientation.X + 1
local Y = Die.Orientation.Y + 1
local Z = Die.Orientation.Z + 1
Die.Orientation = Vector3.new(X, Y, Z)
until Timer == 50
How can I achieve this in a more clean, and smooth way?
(The die is just a part with decals)
local TS = game:GetService("TweenService")
local TI = TweenInfo.new(1)
local Tween = TS:Create(Die, TI, {Orientation = Die.Orientation + Vector3.new(180, 180, 180)}) -- Creates the animation, set to 360 if you want it to turn around all the way
Tween:Play() -- Plays the animation
Tween.Completed:Wait() -- Waits until the animation is done
I’m not too sure how to describe this-- but it isn’t a full-speed kind of rotation. It almost slows down when it is about to reach its destination before looping again. Is there a way to keep a steady rotation flow?
Edit: Here’s my code:
local Die = game.Workspace.Union
local TS = game:GetService("TweenService")
local TI = TweenInfo.new(0.8, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, -1)
local Tween = TS:Create(Die, TI, {Orientation = Die.Orientation + Vector3.new(360, 360, 360)}) -- Creates the animation, set to 360 if you want it to turn around all the way
Tween:Play() -- Plays the animation
wait(4)
Tween:Cancel()
You can see in this video that it slows-down around five and it is displayed for much longer.
I agree, it likes like two axis rotation that’s 180 degrees out of phase. When they overlap a transition occurs, and when one dominates it spins one way.
Hmm, I’m thinking using CFrameFromAxisAngle but it might get tricky using TweenService since it only applies one Tween/property.
The other way is to manually calculate what the proportions each axis is in each standard X,Y,Z orientation, and then tween those accordingly with three tweens like I mentioned earlier.
The third way, which is what I would try before calculating, is to mess around with the numbers and play around with it if you’re not time constrained. You might end up getting something that you like, and you might also end up getting a feel for what the numbers do when you change them.
I am fairly certain that this is rotating on all three axes. The problem is that at some point, two of the axes line up. This creates gimbal lock, which creates the problem you see. There are a couple of ways around this, one of them would be to change the speeds at which the various axes rotate, creating an imperfect yet easy solution which should be adequate for your use-case.
You can also tween the CFrame using quaternion vectors, but I couldn’t even get you started there.
I don’t think using three axes allows for certain sides of the die to be in view of the camera. You can kinda see it in the post earlier where the number 1 is never really in view.
Haven’t exactly tested this out with two axes but I’ll let you know when I do.
Edit: it could also be the timing as someone mentioned earlier. I’ll play around with the amount of axes I’m moving.
I’ve played around with some stuff, however, I still cannot recreate the smooth spinning of dice like the one in the video I posted.
The goal is to have every side of the dice, somehow make an appearance to be in view, so rotating on all axes is what I am trying to accomplish. (sorry for sloppy code, just trying to make it work)
local TweenService = game:GetService('TweenService')
local DiceModel = workspace.Union
local TweenInfo = TweenInfo.new(0.8, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
local Times = 0
local Goal = {}
local function ChangeDirection(Dir)
if(Dir == 1) then
Goal.Orientation = DiceModel.Orientation + Vector3.new(180, 360, 180)
elseif(Dir == 2) then
Goal.Orientation = DiceModel.Orientation + Vector3.new(360, 180, 180)
elseif(Dir == 3) then
Goal.Orientation = DiceModel.Orientation + Vector3.new(180, 180, 360)
end
end
repeat
Goal = {}
ChangeDirection(math.random(1, 2))
local Tween = TweenService:Create(DiceModel, TweenInfo, Goal) -- Creates the animation, set to 360 if you want it to turn around all the way
Tween:Play()
Tween.Completed:Wait()
Times = Times + 1
until Times == 15
The issue with this is that the direction change is very abrupt. Someone mentioned earlier in the post that it may have to do with the timing, but adjusting so you rotate more on one axes seems to have caused certain sides of the die to never make an appearance.
Another issue is that there is a brief moment where when I transition to a new Tween, it pauses. It is very tiny but will be noticeable in my game and an issue. The goal is to give every side of the die a chance to appear an equal amount.
From my experience and calculations, @JarodOfOrbiter, the axes will never compete with each other. The only reason some faces get shown more is because there are constants. Every axis is rotating at a constant and congruent speed, which basically means that you are going to see the same things repeating over and over again. Notice how it shows 5 a lot, but if you were to change the decals around, another number will be shown more.
I would recommend to use:
math.random(-360, 360)
for each axis as that allows each axis to move in both directions at 360 degrees(clockwise and counter-clockwise). You are also going to need some extra code to adjust the time it takes to finish the tween because if each axis only turns by 1 degree it’s going to look unnatural.
I like to use RunService for stuff like this, since it allows for smooth movements.
local RunService = game:GetService("RunService")
local ROTATION_DEGREES = 180
local die = workspace.Union
while true do
local delta = RunService.Stepped:Wait()
local rotation = math.rad(ROTATION_DEGREES * delta)
die.CFrame = die.CFrame * CFrame.Angles(
rotation,
rotation,
rotation
)
end
Alternatively, you can tween this:
local rotations = {
CFrame.Angles(
math.rad(360),
math.rad(360),
math.rad(360)
),
CFrame.Angles(
math.rad(-360),
math.rad(-360),
math.rad(-360)
)
}
local tweenInfo = TweenInfo.new(0.8, Enum.EasingStyle.Linear)
for i = 1, 15 do
local rotation = rotations[Random.new():NextInteger(1, #rotations)]
local tween = TweenService:Create(die, tweenInfo, { CFrame = die.CFrame * rotation })
tween:Play()
tween.Completed:Wait()
end
As it stands, TweenService directly on the part’s orientation was not the best way to accomplish this. However, @VegetationBush suggested I use BodyAngularVelocity to rotate it completely.
I applied TweenService to the AngularVelocity by applying a stronger force on each axes. This is the best way to accomplish the rotation done in the video.
Once again, thank you @VegetationBush and everyone else who tried to help.