How would you tween in a orbital motion

What i want: tween camera from point a to b in an orbital motion

whats wrong: it just goes straight in a line from point a to b

Directly Tweening isn’t really suitable for orbitals. Just use runservice for this scenario

Do you have an idea of how i could do that with runservice?

Have you tried using Bezier curve?

Nope, and I have no clue on how I would use it

If you want a full orbit around a part, then you’d use:

local part = workspace.Part -- change to the part you want to orbit around
local camera = game.Workspace.CurrentCamera
local distance = 10
local speed = 1

local function updateCam()
	local angle = tick() * speed
	local offset = Vector3.new(math.sin(angle), 0, math.cos(angle)) * distance
	camera.CFrame = CFrame.new(part.Position + offset, part.Position)
end
game:GetService("RunService").RenderStepped:Connect(updateCam)

You can use a bit of vector manipulation to make a circle from 3 points A (point 1), B (point 2), and C (a center/focus of the bigger circle created by A and B). We can think of A and B as points lying on the circumference of a circle with center C in a plane P.

Now let’s think of this as a rotation problem:

We want to rotate the vector v_a about the axis N (the normal vector of the plane the circle is in) a total of θ radians. We’re doing this in a time t, which is defined in your provided TweenInfo.

local TweenService = game:GetService("TweenService")

local function orbitalTween(part: BasePart, tweenInfo: TweenInfo, a: Vector3, b: Vector3, c: Vector3): Tween

	local radius0 = (a - c).Magnitude
	local radius1 = (b - c).Magnitude
	
	local v_a = (a - c).Unit
	local v_b = (b - c).Unit
	local r = (b - a).Unit
	local n = r:Cross(v_a).Unit
	local s = v_a:Cross(n).Unit

	local proj_vA_vB = v_b:Dot(v_a)
	local proj_s_vB = v_b:Dot(s)

	local theta = math.atan2(-proj_s_vB, proj_vA_vB)

	local initialRotator = CFrame.fromMatrix(Vector3.zero, s, n, -v_a)
	local proxyNumVal = Instance.new("NumberValue")

	proxyNumVal.Changed:Connect(function(transform: number)
		local rotation = transform*theta
		local radius = radius0 + (radius1 - radius0)*transform
		local currentRotator = initialRotator*CFrame.fromEulerAnglesYXZ(0, rotation, 0)
		local position = c + radius*currentRotator.LookVector
		part.CFrame = CFrame.lookAt(position, c)
	end)

	local tweenObject = TweenService:Create(proxyNumVal, tweenInfo, {Value = 1})
	tweenObject.Completed:Once(function()
		proxyNumVal:Destroy()
	end)

	return tweenObject
end


task.wait(3)

local exampleOrbitalTween = orbitalTween(
	workspace.Test,
	TweenInfo.new(5),
	workspace.A.CFrame.Position,
	workspace.B.CFrame.Position,
	workspace.C.CFrame.Position
)

exampleOrbitalTween:Play()

This produces the following result:

Here’s the place file for the example I used:

OrbitalTest.rbxl (53.5 KB)

Note: You can only call TweenObject:Play() once. To play the tween again, you have to create it using the orbitalTween() function again.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.