Sorry, use to “move” referring to just setting the positions, phrases like “move smoothly” might convey that idea better.
Tween from PointA to PointB (using a separate vector3 variable, not the actual position), and run the interpolated results through the following:
Point_on_surface = MIDPOINT_VECTOR.Unit*SPHERE_RADIUS
In the example place provided, I used FromAxisAngle with the rotation but that seems to be buggy when crossing the Z-axis so you can mess with the rotation elements as you will. I also did not add conditions for moving 180deg (messes with rotation I believe) or a (0,0,0)/nan exemption for the .Unit
All of this is assuming a perfect sphere positioned at the origin point (0,0,0). I’m sure you’re able to figure out workarounds if these cases can’t be met.
SpherePlacement.rbxl (42.7 KB)
Here’s the changed code if you don’t want to open it:
local activeLoop = nil
function GetTweenedValue(endResult,startResult,midPoint)
return(endResult - startResult)*midPoint + startResult
end
function MoveBrick(brick:BasePart,result:RaycastResult)
local TWEEN_DURATION = 1.0
local SPHERE_RADIUS = workspace.Part.Size.X/2
local START_POS,START_ROT,START_ANGLE = brick.Position,brick.CFrame.Rotation:ToAxisAngle()
local END_CFRAME = CFrame.new( result.Position, result.Position+result.Normal )
local END_POS,END_ROT,END_ANGLE = END_CFRAME.Position,END_CFRAME.Rotation:ToAxisAngle()
local EASING_STYLE,EASING_DIRECTION = Enum.EasingStyle.Sine,Enum.EasingDirection.InOut
local interpolatedPosition = START_POS
local interpolatedRotation = brick.CFrame.Rotation
local timePassed = 0
if activeLoop then -- Stops any previous tweens
activeLoop:Disconnect()
end
activeLoop = RunService.Stepped:Connect(function(_,delta)
timePassed += delta
if timePassed > TWEEN_DURATION then -- Checks if goal was reached
activeLoop:Disconnect()
brick.CFrame = END_CFRAME
return
end
local MIDPOINT = TweenService:GetValue(timePassed/TWEEN_DURATION,EASING_STYLE,EASING_DIRECTION) -- Gets 0-1 tween value
local currentPosition = GetTweenedValue(END_POS,START_POS,MIDPOINT) -- Applys tween to position
interpolatedPosition = currentPosition.Unit*SPHERE_RADIUS -- Gets the unit of the current position, then multiplies it by the radius to get a position on the surface of the sphere.
local currentRotation,currentAngle = GetTweenedValue(END_ROT,START_ROT,MIDPOINT),GetTweenedValue(END_ANGLE,START_ANGLE,MIDPOINT)
local interpolatedRotation = CFrame.fromAxisAngle(currentRotation,currentAngle)
brick.CFrame = CFrame.new(interpolatedPosition)*interpolatedRotation
end)
end