I’m trying to recreate the old DVD bouncing animation but with a part in my spawn. I had it working earlier, but inconsistently since it would occasionally get stuck on a side of the floor. I was told to set the opposite direction of the axis it hit on (pos x to neg x, vice versa) but now it’s not working at all.

What I want:

Result:

local x = 10
local z = 10
RunService.Heartbeat:Connect(function(deltaTime)
local position = DESIGN.Position
local function is_outside(component)
return math.abs(position[component]) + DESIGN.Size[component] / 2 >= FLOOR.Size[component] / 2
end
if is_outside('X') then
x *= -math.sign(position.X) * (math.random(90, 110) / 100)
elseif is_outside('Z') then
z *= -math.sign(position.Z) * (math.random(90, 110) / 100)
end
DESIGN.CFrame *= CFrame.new(x * deltaTime, 0, z * deltaTime)
end)

It’s printing when its going out forever just not making any changes to the x/z

You’re not properly checking if the item is outside the bounds properly. You do >= which works for the two sides but not for the opposite side. You need another condition check to see if its outside on the opposite side

Update: got it working, but adding rotation to the equation broke it. I’m assuming I need to use CFrame inside the is_outside function somehow.

local SPIN_SPEED = 0.25
local INITIAL_SPEED = 10
local x = INITIAL_SPEED
local z = INITIAL_SPEED
RunService.Heartbeat:Connect(function(deltaTime)
local position = DESIGN.Position
local function is_outside(component)
return math.abs(position[component]) + DESIGN.Size[component] / 2 >= FLOOR.Size[component] / 2
end
local function get_value(component)
local value = (position[component] > 0 and -INITIAL_SPEED or INITIAL_SPEED) * RNG:NextNumber(0.85, 1.15)
return math.clamp(value, -11, 11)
end
if is_outside('X') then
x = get_value('X')
elseif is_outside('Z') then
z = get_value('Z')
end
DESIGN.CFrame *= CFrame.new(x * deltaTime, 0, z * deltaTime) * CFrame.Angles(0, SPIN_SPEED * deltaTime, 0)
end)