Character's back doesn't face the player's camera (BodyGyro/CFrame/LookAt)

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    I want the character’s back to face the player’s camera after pressing the right mouse button, even if the player points their camera down/up

  2. What is the issue? Include screenshots / videos if possible!
    The character’s back doesn’t face the camera; the character just stops rotating, even if i press “a” or “d” to move

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I couldnt find any solution to the problem over the internet

I am new to scripting. I am currently making a “flying” script. Everything works fine, but the character’s back doesnt face the camera.
I only included the part of the script that doesnt work. There are no errors in the output. If you’d like me to send the whole “flying” script, please tell me.

local cam = workspace.CurrentCamera
local uis = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local PrimaryPart = char.PrimaryPart
            
            local bg = Instance.new("BodyGyro")
            bg.Parent = PrimaryPart
            bg.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
            bg.D = 10000
            bg.Name = "FlightGyro"
            
            ---------------------------------------------------

            local heartbeat = nil

            function LockToCamera()
                local camLv = cam.CFrame.lookVector
                bg.CFrame = CFrame.lookAt(PrimaryPart.Position, (camLv + PrimaryPart.Position) * 10)
                --print((camLv + PrimaryPart.Position) * 10)
                --print(camLv + PrimaryPart.Position)
            end
            
            uis.InputEnded:Connect(function(input)
                if (input.UserInputType == Enum.UserInputType.MouseButton2 and heartbeat) then
                    heartbeat:Disconnect()
                    heartbeat = nil
                    humanoid.AutoRotate = true
                end
            end)


            uis.InputBegan:Connect(function(input, processed)
                if processed then return end
                if (input.UserInputType == Enum.UserInputType.MouseButton2) and flying then
                    humanoid.AutoRotate = false
                    heartbeat = game:GetService("RunService").Heartbeat:Connect(LockToCamera)
                end
            end)

What i want to achieve:

What happens:

local run = game:GetService("RunService")

local players = game:GetService("Players")
local player = players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:WaitForChild("HumanoidRootPart")

local camera = workspace.CurrentCamera

run.RenderStepped:Connect(function()
	hrp.CFrame = CFrame.lookAt(hrp.Position, Vector3.new(camera.CFrame.Position.X, hrp.Position.Y, camera.CFrame.Position.Z)) * CFrame.Angles(0, math.rad(180), 0)
end)

Your script only made the character rotate around the Y axis. I changed the hrp.Position.Y to camera.CFrame.Position.Y and now it works fine. Thanks!

local run = game:GetService("RunService")

local players = game:GetService("Players")
local player = players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:WaitForChild("HumanoidRootPart")

local camera = workspace.CurrentCamera

run.RenderStepped:Connect(function()
	hrp.CFrame = CFrame.lookAt(hrp.Position, Vector3.new(camera.CFrame.Position.X, camera.CFrame.Position.Y, camera.CFrame.Position.Z)) * CFrame.Angles(0, math.rad(180), 0)
end)

I purposefully omitted the Y-axis as it caused the character to tilt weirdly while walking around on a baseplate, if you’re going to include the Y-axis you should write the script as the following.

local run = game:GetService("RunService")

local players = game:GetService("Players")
local player = players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:WaitForChild("HumanoidRootPart")

local camera = workspace.CurrentCamera

run.RenderStepped:Connect(function()
	hrp.CFrame = CFrame.lookAt(hrp.Position, camera.CFrame.Position) * CFrame.Angles(0, math.rad(180), 0)
end)

This way you take out an unnecessary call to “Vector3.new()”, including it would be inefficient.

Additionally, to improve this even further you’d determine if the player is walking/flying and toggle between the two states accordingly.

local run = game:GetService("RunService")

local players = game:GetService("Players")
local player = players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local hrp = character:WaitForChild("HumanoidRootPart")

local camera = workspace.CurrentCamera

run.RenderStepped:Connect(function()
	if humanoid:GetState() == Enum.HumanoidStateType.Running then
		hrp.CFrame = CFrame.lookAt(hrp.Position, Vector3.new(camera.CFrame.Position.X, hrp.Position.Y, camera.CFrame.Position.Z)) * CFrame.Angles(0, math.rad(180), 0)
	else
		hrp.CFrame = CFrame.lookAt(hrp.Position, camera.CFrame.Position) * CFrame.Angles(0, math.rad(180), 0)
	end
end)
1 Like