Character follow mouse not working as intended?

So I have this script that moves the character rotation to the mouses direction, but it only works for a little bit, then stops, any help? There are no output errors either.

	local tool = script.Parent
	local service = game:GetService("RunService")
	
	local success = false
	
	local player = game:GetService("Players").LocalPlayer
	local character = player.Character or player.CharacterAdded:wait()
	local humanoid = character:WaitForChild("Humanoid")
	
	local camera = game.Workspace.CurrentCamera
	local mouse = player:GetMouse()
	
	local offset, magnitude, vector3, cFrame, direcction = nil
	local shoulder, arm, torso, body, neck = nil
	local defaultNeckCO, defaultShoulderCO = nil
	local animate = nil
	
	local shoulderPositionC0, shoulderCFramePositionC1 = nil
	local turnAngle = CFrame.fromEulerAnglesXYZ(math.pi/2, 0, 0)
	local rightangle = CFrame.fromEulerAnglesXYZ(0, 0, math.pi)
	
	local unequipListener
	
	function updateOffset()
		offset = (body.Position.y - mouse.Hit.p.y) / 100
		magnitude = (body.Position - mouse.Hit.p).magnitude / 80
		return offset/magnitude
	end
	
	function updateBodyRotation()
		
		if (camera.Focus.p - camera.CoordinateFrame.p).magnitude > 1 then
			humanoid.AutoRotate = false
			
			vector3 = Vector3.new(mouse.Hit.p.x, body.Position.y, mouse.Hit.p.z)
			
			cFrame = CFrame.new(body.Position, vector3)
			
			body.CFrame = cFrame
		else
			humanoid.AutoRotate = true
		end
		
	end
	
	function animateR15()
	end
	
	
	function animateR6()
	end
	
	function getBodyParts()
		
		body = character.HumanoidRootPart
		
		if humanoid.RigType == Enum.HumanoidRigType.R15 then
			shoulder = character.RightUpperArm.RightShoulder
			arm = character.RightUpperArm
			neck = character.Head.Neck
			torso = character.UpperTorso
	
			animate = animateR15
			
		else
			shoulder = character.Torso["Right Shoulder"]
			arm = character["Right Arm"] 
			neck = character.Torso.Neck
			
			animate = animateR6
			
		end
	
	end
	
	function stopAllFunctions()
		
		pcall(function()
			unequipListener:Disconnect()
		end)
		
		pcall(function()
			service:UnbindFromRenderStep(script.Name)
		end)
			
		pcall(function()
	
			neck.C0 = defaultNeckCO
		end)
			
		pcall(function()
			humanoid.AutoRotate = true
		end)
		
		pcall(function ()
			if humanoid.RigType == Enum.HumanoidRigType.R15 then
				shoulder.Part1 = arm
				arm.Anchored = false
			else
				shoulder.C0 = defaultShoulderCO
			end
		end)
	
	end
	
	function characterFollowTool()
	
		success = pcall(function()
			updateBodyRotation()
			
			animate()
		end)
		
		if not success then
			stopAllFunctions()
		end
		
	end
	
	function onEquip()
		unequipListener = tool.Unequipped:connect(stopAllFunctions)
	
		success = pcall(getBodyParts)
		if not success then
			stopAllFunctions()
		end
	
		service:BindToRenderStep(script.Name, Enum.RenderPriority.Input.Value - 1, characterFollowTool)
	end
	
	tool.Equipped:connect(onEquip)
1 Like

It seems to me like the script that you have is unnecessarily long.
Here is a script that updates the HumanoidRootPart’s CFrame based on the position of the mouse:

local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local Character = Player.Character

spawn(function()
     while wait() do
         local direction = (Mouse.Hit.p - Character.HumanoidRootPart.Position) * Vector3.new(1, 0, 1)
         Character.HumanoidRootPart.CFrame = CFrame.new(Character.HumanoidRootPart.Position, Character.HumanoidRootPart.Position + direction)
     end
end)

I used a spawn function so the rest of the script can run without it being stuck on one thread.

If you prefer a BodyGyro instead of a CFrame value, you can use this instead:

local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local Character = Player.Character

spawn(function()
	 local BodyGyro = Instance.new("BodyGyro", Character.HumanoidRootPart)
     while wait() do
		 BodyGyro.MaxTorque = Vector3.new(0,math.huge,0)
		 BodyGyro.CFrame = CFrame.new(Character.HumanoidRootPart.CFrame.p,Mouse.Hit.p)
		 BodyGyro.P = 1e9
     end
end)
4 Likes

The first one works perfectly, besides the fact that once u unequip it does not stop.

Oh it’s a tool?

Then do this:

Equipped = false

Tool.Equipped:Connect(function()
Equipped = true
 while Equipped do
         local direction = (Mouse.Hit.p - Character.HumanoidRootPart.Position) * Vector3.new(1, 0, 1)
         Character.HumanoidRootPart.CFrame = CFrame.new(Character.HumanoidRootPart.Position, Character.HumanoidRootPart.Position + direction)
     end
end)

Tool.Unequipped:Connect(function()
Equipped = false
end)

That should work to my knowledge.

That loop will crash a game server or time out in Studio. There’s no wait in it. Might want to add the wait in the loop rather than as the condition.

Not always the case, in my experience this only happens when nothing is being done, or it’s a loop that is constantly checking for parameters.

Wouldn’t hurt to add a wait() though.

Yes it is always the case. A while loop that doesn’t have an interval will crash, regardless of whether it has contents in it or not. Conditional checking (the content between while-do) is the same as an if statement and it happens every iteration, doesn’t mean anything for the loop.

1 Like

I think I fixed it.

local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local Character = Player.Character
local Tool = script.Parent

Equipped = false

Tool.Equipped:Connect(function()
if Equipped == false then
Equipped = true
 while Equipped do
         local direction = (Mouse.Hit.p - Character.HumanoidRootPart.Position) * Vector3.new(1, 0, 1)
         Character.HumanoidRootPart.CFrame = CFrame.new(Character.HumanoidRootPart.Position, Character.HumanoidRootPart.Position + direction)
     end
end)

Tool.Unequipped:Connect(function()
Equipped = false
end)

No i did not fix it, any help?

Please do some debugging and looking over your code, as well as the console if your code doesn’t work, before posting that something doesn’t work. I copy-pasted your current code into Studio and there is a red underline right there.

image

This problem could be resolved through proper indentation. Your code is missing an extra end above the end with a closing bracket on it. As well, your code crashes as the loop runs constantly. Therefore, add a wait below.

Fixed:

local Player = game:GetService("Players").LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Mouse = Player:GetMouse()
local Tool = script.Parent

local Equipped = false

Tool.Equipped:Connect(function()
	if Equipped == false then
		Equipped = true
		while Equipped do
			local direction = (Mouse.Hit.p - Character.HumanoidRootPart.Position) * Vector3.new(1, 0, 1)
			Character.HumanoidRootPart.CFrame = CFrame.new(Character.HumanoidRootPart.Position, Character.HumanoidRootPart.Position + direction)
			wait()
		end
	end
end)

Tool.Unequipped:Connect(function()
	Equipped = false
end)

That being said, no errors, but my character isn’t turning around, so there’s some fixes that need to be applied to the calculations.

It’s in the backpack so Mouse.Hit is returning nil, here’s a kind of hacky fix.

local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local Character = Player.Character
local Tool = "Pistol"

Equipped = false

Player.Backpack.ChildRemoved:Connect(function(EquippedTool)
	if Tool == EquippedTool.Name then
	Equipped = true
	 while Equipped do
			 wait()
	         local direction = (Mouse.Hit.p - Character.HumanoidRootPart.Position) * Vector3.new(1, 0, 1)
	         Character.HumanoidRootPart.CFrame = CFrame.new(Character.HumanoidRootPart.Position, Character.HumanoidRootPart.Position + direction)
	     end
	end
end)

Player.Backpack.ChildAdded:Connect(function(UnequippedTool)
if UnequippedTool.Name == Tool then
	Equipped = false
	end
end)

Put this script into PlayerGui

I obviously realised the error, thats why I said “it didnt work” it doesnt work after I fixed the )

Why would Mouse.Hit return nil? The PlayerMouse is unassociated with a Tool being equipped or not. It’d always return an accurate CFrame of where the mouse is in 3D space.


@Pooglies

If you realised it, it’d help to fix it first before posting that it’s not working, along with a statement about how there’s no console errors and provide the updated piece of code. You supposedly realising the error is not obvious if I posted your current code with an unaddressed red underline.

I’m assuming once the tool is equipped it is now a member of the server and so it will not work anymore. I have no idea, but that is the fix I found for the problem without using remote events.

The script is still timing out.

Not the case. Tool equipping is replicated but the server isn’t necessarily authoritative of it. There’s still a divide between client and server functionality. Guess it’s worth noting but from the client, the mouse object is passed in equipped, so you don’t have to use GetMouse.

@Pooglies That’s my mistake. I didn’t add a wait. Though you could’ve also added one yourself rather than raw copy-pasting my code and telling me it doesn’t work without debugging it.

When I tried it on my own, the Equipped event was not firing on the local script, that is why I came to that conclusion.

I just checked @Pooglies, and it should be working if you changed the name of the tool in the script.

This works fine

local Player = game:GetService("Players").LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Mouse = Player:GetMouse()
local Tool = script.Parent

local Equipped = false

Tool.Equipped:Connect(function()
	if Equipped == false then
		Equipped = true
		while Equipped do
			local direction = (Mouse.Hit.p - Character.HumanoidRootPart.Position) * Vector3.new(1, 0, 1)
			Character.HumanoidRootPart.CFrame = CFrame.new(Character.HumanoidRootPart.Position, Character.HumanoidRootPart.Position + direction)
			wait()
		end
	end
end)

Tool.Unequipped:Connect(function()
	Equipped = false
end)

but this is a bug that is weird, when you move?

Try the BodyGyro version that I gave you earlier, but modify it to your needs.

This may have been an issue with the repro then. My personal repro, I later realised, wasn’t working because I was using a no-handle tool with RequiresHandle still checked off. Equipped fires on both the client and the server respectively. The PlayerMouse is passed as a parameter to the client version.