I want to make it so an object will orbit around another object, while continuously following them.
local CenterPart = -- part
local Satellite = -- part 2
local R = 5
local THETA = 0
local W = 1
game:GetService("RunService").Heartbeat:Connect(function(dt)
THETA = (THETA + W * dt) % (2 * math.pi)
local goal = CenterPart.CFrame * CFrame.new(5 * math.cos(THETA), 0, 5 * math.sin(THETA))
Satellite.CFrame = Satellite.CFrame:Lerp(goal, dt)
end)
Before giving me the script, can you explain it?
I’ll try explain you:
1 -game:GetService("RunService").Heartbeat:Connect(function(dt)
2- THETA = (THETA + W * dt) % (2 * math.pi)
3 - local goal = CenterPart.CFrame * CFrame.new(5 * math.cos(THETA), 0, 5 * math.sin(THETA))
4 - Satellite.CFrame = Satellite.CFrame:Lerp(goal, dt)
end)
1 - basic function. Every frame rendered, RunService
will connect function with delay time
(time between frames)
2 - this’s part of counting rotation. Because cos(math.pi * 2) = cos(0) = cos(math.pi * 4)
and etc (pi = 180 degrees, because radians). Every frame, THETA
increases by W * delay time
, and if it greater than 2 pi
, it cuts it by them (just to avoid giant numbers).
3-4 - For actual last point, I rewrite it to:
Satellite.CFrame = CenterPart.CFrame * CFrame.new(5 * math.cos(THETA), 0, 5 * math.sin(THETA))
And here, we are setting CFrame of your spinning part
NOTE: THIS PART WON’T BE ROTATED, IT WILL CHANGE POSITION ONLY!!! math.sin() and math.cos() are creating circle, like this:
(0 rad / 0 deg = 1 cos and 0 sin;
pi / 2 rad / 90 deg = 0 cos and 1 sin;
pi rad / 180 deg = -1 cos and 0 sin;
3 pi / 2 rad / 270 deg = 0 cos and -1 sin)
And using this knowledge, we can write easy formula for finding point where part should be:
5 * math.cos(THETA), 0, 5 * math.sin(THETA)
(5 in this example - number, how far from center will spin your part)
(Sorry if I badly explain everything here)
What’s cos, and why are the variables set to 5, 0, and 1?
5 - you can change it to any number - 10, 100, 92489012854 - it just sets radius
0 - height. If you set it to any other number, spinning will be offsetted by axis Y by x studs.
1… where you find 1?
cos - this’s cosinus. For understanding what’s this, you need start learn trigonometry, but for now, you should know this:
Your question - why I need triangles here?
Answer: you need just understand that here we needn’t triangle as much as you can mean. We need here look at 2 lines: AC and BC, and corner a. Line AB for understanding MUST BE CONSTANT!
. The more angle a - the longer line BC and shorter line AC. AC
- Example of COSINUS
, BC
- example of SINUS
I was lerping so that when the Center is moved, the satellite doesn’t get forcibly repositioned to the new position. You can change the “lerp aggression” by mutliplying dt by some amount between 0 - 60.
You’re right that technically it isn’t ever actually reaching the points on the circle at R ( cos(theta), sin(theta)), but it is still a circular orbit and that’s good enough.
Also thanks for explaining it for me, very thorough - I wasn’t at my PC to do so.
5 Is the radius (distance away from the center part), 0 is the initial (start) angle, and 1 is the angular speed ( increasing this number will increase the rate of orbit )
Boot up studio and execute it - it’s smooth. Also while running, move the center part and you’ll also see how it smoothly follows the center part around
oof. sorry, i was really stupid at that. During tests it really smooth. Sorry for argue.
You’re right about one thing tho that it won’t actually reach the true values that it’s supposed to, but I was happy sacrificing that.
Btw could you edit your post where you said the lerp was wrong ?
here is more code that might help you understand
local runService = game:GetService("RunService")
local targetPart = ...
local orbitPart = ...
-- distance from the center of the circle
local radius = 5
-- angle in radians that the part has rotated we start at a angle of 0
local theta = 0
-- rotation speed per second in radians i used math.rad to convert 1 degree to 0.0174533 radians
local speed = math.rad(1)
-- call this function every frame
runService.Heartbeat:Connect(function(deltaTime)
-- increment theta by the speed multiplied by the delta time since the last time this function was called
theta += speed * deltaTime
-- you dont need to do this but this will wrap theta so the value does not get to high its a bit like doing (if theta >= 2 * math.pi then theta -= 2 * math.pi end)
theta = theta % (2 * math.pi)
-- use sin and cos to make a circle
local offset = Vector3.new(math.sin(theta), 0, math.cos(theta))
-- multiple the circle by radius
offset *= radius
-- position orbitPart to the same position as targetPart + the circle offset
orbitPart.Position = targetPart.Position + offset
end)