My whirlpool code is trash

The idea behind this script is to make an object move in a circle about the center of an object on contact using BodyPositions. I need to have control over the force. For some reason, the value of theta jumps and the player is moved to the other side of the circle.

https://gyazo.com/251afcd72a4c4470f91c7773c466fc8b
https://gyazo.com/aa4f205558410630c010f99708608d3a

 local debounce = false
--setup poolsize with xz plane and r 
local pool = script.Parent
local poolSize = script.Parent.Size
local function onTouched(part)
	if debounce then return end
	debounce = true
	--make part equal to its highest parent
	while part.Parent ~= workspace do
		part = part.Parent
	end
	--if model make it humanoidrootpart or primarypart
	if part:IsA("Model") then part = part.HumanoidRootPart or part.PrimaryPart end
	
	if not part:FindFirstChild("WhirlpoolForce") then 
		local bpf = Instance.new("BodyPosition")
		local bav = Instance.new("BodyAngularVelocity")
		local bps = Instance.new("BodyPosition")
		bav.Name = "WhirlpoolSpin"
		bpf.Name = "WhirlpoolForce"
		bps.Name = "WhirlpoolSuck"
		bpf.Parent = part
		bpf.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
		bav.Parent = part
		--bps.Parent = part
		
		--get part xzplane difference/magnitude
		local theta = 0
		local r
		
		
		local function xzMag (vec31,vec32) return Vector2.new(vec31.X-vec32.X,vec31.Z-vec32.Z).Magnitude end
		--vector from vec31 to vec32
		local function xzVec (vec31,vec32) return Vector2.new(vec31.X-vec32.X,vec31.Z-vec32.Z) end
		local function getAngle (vec) if vec.X == 0 and vec.Y > 0 then return math.pi/2  elseif vec.X == 0 then return -math.pi/2 else return math.atan(vec.Y/vec.X) end end
		local function boundTheta(theta) if theta > 2*math.pi then return theta - 2*math.pi else return theta end end		
		--r is the distance between the part and the center of the whirlpool on the xz plane
		while true do 
				r = xzMag(pool.Position,part.Position)
				theta = getAngle(xzVec(pool.Position,part.Position)) + math.pi/4
				theta = boundTheta(theta)
				bpf.Position = Vector3.new(r*math.cos(theta),40,r*math.sin(theta))+pool.Position
				print(bpf.Position) 
				wait() 
				
		end
	end
	debounce = false
end

script.Parent.Touched:Connect(function(part) onTouched(part)end)
1 Like

no need for that long of a script
just do this

local positionToOrbit = Vector3.new()

while game:GetService("RunService").Heartbeat:Wait() do
     local tick = tick()
     part.CFrame = CFrame.new(part.Position + Vector3.new(math.sin(tick), 0, math.cos(tick)), positionToOrbit)
end
1 Like

Sorry, I forgot to include that I also need control of the force. Although, thank you for exposing me to heartbeat, it’s better than what I’m doing.

1 Like

The issue was that arctan can only measure angles between 0 and 180 degrees, which left half the circle unaccounted for. The solution was to check the current position of the player and compare it to the target position, if it was some multiple of r, then add 180 degrees to theta.