Orbit a vector by a center based on velocity

What I am trying to achieve is a sort of orbiting system where a object in space orbits around a certain vector point while maintaining velocity. Say a character was falling and they wanted to swing, they would press a button while falling and they would swing based on that speed and direction.

I literally don’t have any idea where to start honestly. I’ve tried to look for solutions or help here but couldn’t find it. Also I have tried completely manipulating the CFrame of the vector to make it orbit and also tried using BodyMovers.

I found this script on the Developer Hub and tried it but wasn’t getting the results I needed. I’m not the best at this kind of math so that’s why I assume that I’m struggling.

local Rot = 0

local OrbitTime = 2
			local OrbitRadius = (part.Position - centerPos).Magnitude
			local OrbitEclipse = 1
			local Rotation = CFrame.Angles(0, 0, 0)
			
			local OrbitSpeed = pi * 2 / OrbitTime
			OrbitEclipse = OrbitEclipse * OrbitRadius
			
			_RS.Stepped:Connect(function(Time, DeltaTime)
				Rot = Rot + DeltaTime * OrbitSpeed
				root.CFrame = Rotation * CFrame.new(
					sin(Rot) * OrbitEclipse,
					0,
					cos(Rot) * OrbitRadius
				) + RightHookPoint
			end)

Any help would be appreciated. Thanks in advance.

3 Likes

When one body orbits another, its movement at any given time is perpendicular to the translation between the bodies.
[image]

This script will make two parts, one of which is unanchored and orbits another.

local part1 = Instance.new("Part")
part1.Position = Vector3.new(20, 5, 0)
part1.Parent = workspace

local part2 = Instance.new("Part")
part2.Position = Vector3.new(0, 5, 0)
part2.Anchored = true
part2.Parent = workspace

-- BodyVelocity is used to counteract gravity
-- Setting Velocity of part1 every Stepped works too, but lets the part drop down slowly
local force = Instance.new("BodyVelocity", part1)
force.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
-- force.P = math.huge

local axis = Vector3.new(0, 1, 0) -- Axis that the part is spinning around
local speed = 50

game["Run Service"].Stepped:Connect(function()
	force.Velocity = (part1.Position - part2.Position):Cross(axis).Unit * speed
	-- (part1.Position - part2.Position): vector pointing from part2 to part1 whose magnitude is the distance between them
	-- :Cross(axis): vector that is perpendicular to both the rotation axis and the translation
	-- .Unit * speed: force magnitude to be 20
	print((part1.Position - part2.Position).Magnitude) -- watch the distance between them grow slowly :(
end)

I’m using Velocity here (instead of CFraming like the script you found does) because it generally keeps physics correct. Things that you hit while orbiting will be knocked away etc.

Say a character was falling and they wanted to swing, they would press a button while falling and they would swing based on that speed and direction.

Let’s see… we have the original Velocity of the player and we want to keep going that way.
Modify the variables in the above script thus:

local velocity -- velocity of the player, find it however you like
local posPlayer
local posTarget

local speed = velocity.Magnitude -- retain current speed
local axis = (posTarget - posPlayer):Cross(velocity).Unit -- vector that has length of 1 and is perpendicular to both direction of movement and translation between player and target
-- watch the distance between them grow slowly :(

I put this comment in the code because that happens. You might want to connect the player and the target with a RodConstraint.

If the player (or part, in the test script) collides with something, it won’t bounce back. This is because the BodyVelocity is very stubborn. Setting Velocity and removing gravity from the player would help here, as would updating speed based on the current velocity every step, so that it can change on collision.

All of this is best done in a local script. No server script involvement or remote events are needed, just set the character’s velocity/position/whatever. The BodyVelocity will work even if it doesn’t exist on the server, because it does exist for the client, and the client tells the server where the character is anyway.

4 Likes