ODM Gear Orbiting

Hello! I am currently attempting to create realistic ODM gear based on the show Attack on Titan. The mechanics consist of a movement system where players can move their mouse over a wall or object and press Q / E on their keyboard to initiate a grapple onto the object. I already have the movement working so far, but I’ve run into a road block. I wanted to incorporate an orbiting-like mechanic to the system that slowly orbits a player around the object they’ve grappled on, in a circle. I’ve tried several methods of doing this, like using AngularVelocity, BodyAngularVelocity, CylindricalConstraints, and simply editing my BodyVelocity (the main character mover) to move the character in a circle around the object, which didn’t work. At this point, I have no idea what to do. Here’s a portion of my current code that handles movement with the ODM gear:

ReplicatedStorage.Assets.Remotes.GrappleBegin.OnServerEvent:Connect(function(Player, HP)
	local Character = Player.Character or Player.CharacterAdded:Wait()
	local Root = Character:WaitForChild("HumanoidRootPart")
	local Humanoid = Character:WaitForChild("Humanoid")
	local ODM = Character:FindFirstChild("ODM")
	
	if HP and ODM then
		local Params = RaycastParams.new()
		Params.FilterDescendantsInstances = { Character; ODM }
		Params.FilterType = Enum.RaycastFilterType.Exclude
		
		local Dir = (HP - Root.Position).Unit
		local _Filter = workspace:Raycast(Root.Position, Dir * 400, Params)
		
		if _Filter then
			if _Filter.Instance then
				if _Filter.Instance.Name ~= "Baseplate" then
					ReplicatedStorage.Assets.Remotes.CLIENT_2:FireClient(Player)
					
					local AttchHolder = Instance.new("Part", workspace)
					AttchHolder.Transparency = 1
					AttchHolder.CanCollide = false
					AttchHolder.Anchored = true
					AttchHolder.Position = _Filter.Position
					AttchHolder.Name = Player.Name.."_ODM_GRAPPLE_POS"

					local Identifier = Instance.new("BoolValue", Character)
					Identifier.Name = "IsGrappling"

					ReplicatedStorage.Assets.Remotes.CreateClientBillboard:FireClient(Player, AttchHolder)

					ReplicatedStorage.Assets.Remotes.FOV_Out:FireClient(Player)
					ODM.Root.Shot:Play()
					ODM.Gas.Emitter.Boost.Enabled = true
					ODM.Gas.Emitter.Trail.Enabled = true

					task.delay(ODM.Root.Shot.TimeLength / 2, function()
						ODM.Gas.Burst:Play()
						ODM.Gas.Emit:Play()
					end)

					Root.CFrame = CFrame.lookAt(Root.Position, AttchHolder.Position)

					local Attch0 = Instance.new("Attachment", Root)
					Attch0.Name = "ODM_ATTACHMENT"

					local Attch1 = Instance.new("Attachment", AttchHolder)

					local RightBeam = ODM.LeftGrapple3.Beam
					local LeftBeam = ODM.RightGrapple3.Beam

					RightBeam.Attachment1 = Attch1
					LeftBeam.Attachment1 = Attch1
					
					local BodyVelocity = Instance.new("BodyVelocity", Root)
					BodyVelocity.MaxForce = Vector3.new(5000, 5000, 5000)
					BodyVelocity.P = 25

					local Direction = (AttchHolder.Position - Root.Position).Unit
					local Rotation = CFrame.lookAt(Vector3.new(0, 0, 0), Vector3.new(Direction.X, 0, Direction.Z))

					local BodyGyro = Instance.new("BodyGyro", Root)
					BodyGyro.D = 100
					BodyGyro.P = 5000
					BodyGyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
					BodyGyro.CFrame = Rotation
					
					local Connection
					local Connection2

					task.delay(1, function()
						for i, x in pairs(Character:GetDescendants()) do
							if x:IsA("BasePart") then
								local __Connection

								__Connection = x.Touched:Connect(function(Hit)
									if not game.Players:GetPlayerFromCharacter(Hit.Parent) and Hit ~= _Filter.Instance or Hit.Name == "Baseplate" and ReplicatedStorage.Assets.Remotes.CollisionCheckRunner:FireClient(Player) == true then
										if Character:FindFirstChild("IsGrappling") then
											Identifier:Destroy()
											BodyGyro:Destroy()
											BodyVelocity:Destroy()
											AttchHolder:Destroy()
											ODM.Gas.Emitter.Boost.Enabled = false
											ODM.Gas.Emitter.Trail.Enabled = false
											ReplicatedStorage.Assets.Remotes.FOV_In:FireClient(Player)
											ODM.Gas.Emit:Stop()

											if not ODM.Root.Retract:FindFirstChild("Cooldown") then
												ODM.Root.Retract:Play()
											end

											Connection:Disconnect()
										end
									end
								end)

								Identifier.Destroying:Connect(function()
									__Connection:Disconnect()
								end)
							end
						end
					end)
					
					Connection2 = _Filter.Instance.Touched:Connect(function(Hit)
						if Hit then
							if game.Players:GetPlayerFromCharacter(Hit.Parent) == Player then
								if BodyVelocity and AttchHolder and BodyGyro then
									BodyGyro:Destroy()
									BodyVelocity:Destroy()
									AttchHolder:Destroy()
									ODM.Gas.Emitter.Boost.Enabled = false
									ODM.Gas.Emitter.Trail.Enabled = false
									ReplicatedStorage.Assets.Remotes.FOV_In:FireClient(Player)
									ODM.Gas.Emit:Stop()

									if not ODM.Root.Retract:FindFirstChild("Cooldown") then
										ODM.Root.Retract:Play()
									end

									Identifier:Destroy()
									Connection2:Disconnect()
									Connection:Disconnect()
								end
							end
						end
					end)
					
					
					Connection = RunService.Heartbeat:Connect(function(DT)
						if AttchHolder then
							local UpdatedDir = (AttchHolder.Position - Root.Position).Unit
							local UpdatedRotation = CFrame.lookAt(Vector3.new(0, 0, 0), Vector3.new(UpdatedDir.X, 0, UpdatedDir.Z))
							
							BodyVelocity.Velocity = (AttchHolder.Position - Root.Position).Unit * 100
							BodyGyro.CFrame = UpdatedRotation
						end
					end)
				end
			end
		end
	end
end)

I’ve been trying to implement this mechanic for multiple days with no successful results, so if anyone has a potential solution, please let me know. Thanks!

3 Likes

You’d probably need to do some maths. Look into some pendulum simulations and understand how they work. I may be 50% asian but I still suck at math, so thats all I can say. :laughing: