I am making a third person, over the shoulder, camera for my game, but how my script is rotating the character is pretty buggy.
As you can see and if you try the code out yourself, the character is glitching out when moving in different directions and rotating around, especially when you move backwards.
I want the camera and character to be more smooth and prevent this laggy type of movement.
Here is my code:
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local connection = nil
local enabled = false
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local camera = workspace.CurrentCamera
local root = character.PrimaryPart
local function RotateCharacter()
local lookVector = camera.CFrame.LookVector
local flatVector = Vector3.new(lookVector.X, 0, lookVector.Z).Unit
local targetCFrame = CFrame.new(root.Position, root.Position + flatVector)
root.CFrame = targetCFrame
end
local tweenInfo = TweenInfo.new(0.2, Enum.EasingStyle.Quint, Enum.EasingDirection.Out)
local function TweenOffset(bool)
if bool then
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
local tween = TweenService:Create(character.Humanoid, tweenInfo, {CameraOffset = Vector3.new(2, 0.25, 0)})
tween:Play()
if connection then connection:Disconnect() end
connection = RunService.PreRender:Connect(function()
RotateCharacter()
end)
else
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
local tween = TweenService:Create(character.Humanoid, tweenInfo, {CameraOffset = Vector3.new(0, 0, 0)})
tween:Play()
if connection then connection:Disconnect() end
end
end
UserInputService.InputBegan:Connect(function(input, processed)
if processed then return end
if input.KeyCode == Enum.KeyCode.Z then
enabled = not enabled
TweenOffset(enabled)
end
end)
I faced this exact same problem a while back. It took me 3 years to figure out a solution. Here’s the code. It includes obstruction detection, so the camera moves forward in front of a part and not right through it!
function CameraController:EnableThirdPerson()
if os.time() - self.TimeSinceDeactivation < 1 then
task.cancel(self.DeactivationTask)
self.DeactivationTask = nil
end
local Character: Model = self.Player.Character or self.Player.CharacterAdded:Wait()
local Humanoid: Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart: BasePart = Character:WaitForChild("HumanoidRootPart")
self.LerpTo = self.RightCameraOffset
Camera.CameraType = Enum.CameraType.Scriptable
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
UserInputService.MouseIconEnabled = false
RunService:BindToRenderStep(self.ThirdPersonRender, Enum.RenderPriority.Camera.Value, function(DeltaTime)
self.GlobalCameraOffset = self.GlobalCameraOffset:Lerp(self.LerpTo, 0.1)
local StartCFrame = CFrame.new(HumanoidRootPart.CFrame.Position) * CFrame.Angles(0, math.rad(self.CameraAngleX), 0) * CFrame.Angles(math.rad(self.CameraAngleY), 0, 0)
local CameraCFrame = StartCFrame:PointToWorldSpace(self.GlobalCameraOffset)
local CameraFocus = StartCFrame:PointToWorldSpace(Vector3.new(self.GlobalCameraOffset.X, self.GlobalCameraOffset.Y, -1000000))
UserInputService.MouseDeltaSensitivity = 0.5
Camera.CFrame = CFrame.lookAt(CameraCFrame, CameraFocus)
local LookCFrame = CFrame.lookAt(HumanoidRootPart.Position, Camera.CFrame:PointToWorldSpace(Vector3.new(0, 0, -1000000)))
HumanoidRootPart.CFrame = HumanoidRootPart.CFrame:Lerp(CFrame.fromMatrix(HumanoidRootPart.Position, LookCFrame.XVector, HumanoidRootPart.CFrame.YVector), 0.1)
Humanoid.AutoRotate = false
local RaycastParameters = RaycastParams.new()
RaycastParameters.FilterType = Enum.RaycastFilterType.Exclude
RaycastParameters.FilterDescendantsInstances = {Character}
local RaycastResult = workspace:Raycast(Character.Head.Position, Camera.CFrame.Position - Character.Head.Position, RaycastParameters)
if RaycastResult then
local HitPart, HitPosition = RaycastResult.Instance, RaycastResult.Position
Camera.CFrame = (Camera.CFrame - (Camera.CFrame.Position - HitPosition)) + (Character.Head.Position - Camera.CFrame.Position).Unit
end
end)
end