Having problem with my character looking at the mouse position

Hey everyone, I’m working on a third-person aiming script, but I’m running into an issue. My char isn’t looking at the mouse position correctly when aiming. I’ve tried a few things, but I’m still having trouble getting it to work as expected. Has anyone any idea on how to fix this?

image

wait()

local uis = game:GetService("UserInputService")
local pls = game:GetService("Players")
local rs = game:GetService("RunService")
local ts = game:GetService("TweenService")
local rep = game:GetService("ReplicatedStorage")

local wepmod = require(rep.Modules.Weapons)
local playermod = require(pls.LocalPlayer:WaitForChild("PlayerScripts"):WaitForChild("PlayerModule"))

local plr = pls.LocalPlayer

repeat
	task.wait()
until plr.Character

local char = plr.Character
local cam = workspace.CurrentCamera

local curtool = nil
local isaiming = false
local aimpos = Vector3.new(7, 1, 8)
local goalpos = aimpos
local normfov = 70
local aimfov = normfov - 3
local smoothspd = 0.2
local aimoffspeed = 0.15
local normzoom = plr.CameraMinZoomDistance
local aimzoom = plr.CameraMaxZoomDistance
local curmaxzoom = aimzoom
local curminzoom = normzoom
local zoomspd = 0.1
local aimblock = false

local recoilrot = Vector3.new(0, 0, 0)
local recoilspd = 0.1

local function firstperson()
	return (char.Head.Position - cam.CFrame.Position).Magnitude < 1
end

local function goodtool(tool)
	if not tool then return false end
	local info = wepmod.GetWeaponInfo(tool.Name)
	return info ~= nil
end

local aimanim = script:FindFirstChild("AimAnimation")
local track

local function setupchar(char)
	local hum = char:WaitForChild("Humanoid")
	track = hum:LoadAnimation(aimanim)
	local function startaim()
		if not goodtool(curtool) or isaiming or aimblock then return end
		if firstperson() then return end
		char:WaitForChild("Info").Aiming.Value = true
		aimblock = true
		isaiming = true
		ts:Create(cam, TweenInfo.new(0.3, Enum.EasingStyle.Sine, Enum.EasingDirection.Out), {FieldOfView = aimfov}):Play()
		curmaxzoom = 3
		curminzoom = 3
		uis.MouseBehavior = Enum.MouseBehavior.LockCenter
		playermod:ToggleShiftLock(false, true, true)
		track:Play()
		wait(0.3)
		aimblock = false
	end

	local function stopaim()
		if not isaiming then return end
		char:WaitForChild("Info").Aiming.Value = false
		isaiming = false
		ts:Create(cam, TweenInfo.new(0.3, Enum.EasingStyle.Sine, Enum.EasingDirection.Out), {FieldOfView = normfov}):Play()
		curmaxzoom = aimzoom
		curminzoom = normzoom
		uis.MouseBehavior = Enum.MouseBehavior.Default
		track:Stop()
		playermod:ToggleShiftLock(true, true, true)
	end

	uis.InputBegan:Connect(function(input, processed)
		if processed then return end
		if input.UserInputType == Enum.UserInputType.MouseButton2 then
			startaim()
		elseif input.KeyCode == Enum.KeyCode.Q then
			goalpos = Vector3.new(-14, 1, 8)
		elseif input.KeyCode == Enum.KeyCode.E then
			goalpos = Vector3.new(6, 1, 8)
		end
	end)

	uis.InputEnded:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton2 then
			stopaim()
		end
	end)

	char.ChildAdded:Connect(function(child)
		task.wait()
		if child:IsA("Tool") then
			curtool = child
		end
	end)

	char.ChildRemoved:Connect(function(child)
		if child == curtool then
			curtool = nil
			stopaim()
		end
	end)

	rs.RenderStepped:Connect(function()
		aimpos = aimpos:Lerp(goalpos, aimoffspeed)
		plr.CameraMaxZoomDistance += (curmaxzoom - plr.CameraMaxZoomDistance) * zoomspd
		plr.CameraMinZoomDistance += (curminzoom - plr.CameraMinZoomDistance) * zoomspd
		if recoilrot.Magnitude > 0.01 then
			cam.CFrame *= CFrame.Angles(math.rad(recoilrot.X), math.rad(recoilrot.Y), 0)
			recoilrot = recoilrot:Lerp(Vector3.new(0, 0, 0), recoilspd)
		end
		if isaiming and char:FindFirstChild("Head") then
			local root = hum.RootPart
			local lookdir = cam.CFrame.LookVector
			local rootpos = root.Position
			root.CFrame = CFrame.new(rootpos.X, rootpos.Y, rootpos.Z) * CFrame.Angles(0, math.atan2(lookdir.X, lookdir.Z), 0)
			local offset = cam.CFrame.RightVector * aimpos.X
			local tgtpos = char.Head.Position - (lookdir * aimpos.Z) + Vector3.new(0, aimpos.Y, 0) + offset
			local tgtcframe = CFrame.new(tgtpos, tgtpos + lookdir)
			cam.CFrame = cam.CFrame:Lerp(tgtcframe, smoothspd)
		end
	end)
end

plr.CharacterAdded:Connect(setupchar)
if plr.Character then
	setupchar(plr.Character)
end

1 Like

Try replacing this section of your code:

local offset = cam.CFrame.RightVector * aimpos.X
local tgtpos = char.Head.Position - (lookdir * aimpos.Z) + Vector3.new(0, aimpos.Y, 0) + offset
local tgtcframe = CFrame.new(tgtpos, tgtpos + lookdir)

with this:

local mouse = plr:GetMouse()
local mouseHit = mouse.Hit.Position 
local tgtpos = mouseHit + Vector3.new(0, aimpos.Y, 0)
local tgtcframe = CFrame.new(cam.CFrame.Position, tgtpos)

mouse.Hit.Position gives the position of the mouse’s aim in the world.

This ensures the target position (tgtpos) is dynamically adjusted to where the mouse is pointing, while maintaining a vertical offset for aiming (aimpos.Y).

That sadly did not help, my camera just slowly goes up now.

Your problem is here

math.atan2(lookdir.X, lookdir.Z)

math.atan2 might get a little tricky when you’re using it to make something face a position, since you’re making a character face a position in this case, you can just use CFrame.new(pos,lookatpos) or CFrame.lookAt() combined with ToOrientation

local _,Yaw,_ = CFrame.new(rootpos,targetlookatpos):ToOrientation()

root.CFrame = CFrame.new(rootpos) * CFrame.Angles(0,Yaw,0)

If you still want to use math.atan2, try swapping the orders of the X and Z

example

math.atan2(X,Z)

math.atan2(Z,X)

math.atan2(Y,X)

math.atan2(-X,Z)

and so on

Sadly, that completely broke the script. :frowning:

It worked fine for me, just tested it, how come does it “break” your script