i’m working on a first-person game. for the most part, it’s going swimmingly. that was, until just now. when i added sine waves to make it feel like you were actually walking (with purpose), the camera snaps when i stop walking. however, when i try to use linear interpolation, it made the camera bug out completely. i’m stumped. how can i make it smoothly reset to the original cframe after the character stops walking?
the goods:
a video that describes my issue:
the source code:
-- services
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
-- wait for character to fully load in; prevents output being flooded with errors
local client = Players.LocalPlayer
repeat task.wait() until client.Character
local character = client.Character
local head = character:WaitForChild("Head")
local root_part = character:WaitForChild("HumanoidRootPart")
local humanoid = character:WaitForChild("Humanoid")
local current_camera = workspace.CurrentCamera
local camera_rotation = Vector2.new(0, 0)
local height_offset = head.Position.Y - root_part.Position.Y
local cam_connection, root_connection
local attachment = Instance.new("Attachment")
attachment.Name = "spectate_point"
attachment.Parent = root_part
local function toggle_player(enabled)
if enabled then
for _, child in ipairs(character:GetDescendants()) do
if child:IsA("BasePart") and child.Name ~= "HumanoidRootPart" then
child.LocalTransparencyModifier = 1
if child:IsA("Decal") then
child.LocalTransparencyModifier = 1
end
end
end
else
for _, child in ipairs(character:GetDescendants()) do
if child:IsA("BasePart") and child.Name ~= "HumanoidRootPart" then
child.LocalTransparencyModifier = 0
if child:IsA("Decal") then
child.LocalTransparencyModifier = 0
end
end
end
end
end
local function update_camera()
local player_camera = root_part:FindFirstChild("spectate_point")
if not player_camera then
return
end
if humanoid.Health > 0 then
-- no "up down, up down", sorry cory
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
camera_rotation += UserInputService:GetMouseDelta() * math.rad(UserInputService.MouseDeltaSensitivity / 6)
camera_rotation = Vector2.new(camera_rotation.X, math.clamp(camera_rotation.Y, math.rad(-0), math.rad(0)))
if humanoid.MoveDirection.Magnitude ~= 0 then
local current_time = tick()
local frequency = 1.8 -- controls the speed
local amplitude = 0.56 -- controls the height
local y_offset = amplitude * math.sin(2 * math.pi * frequency * current_time)
local camera_pos = Vector3.new(0, height_offset + y_offset, 0) + root_part.Position
player_camera.WorldCFrame = CFrame.new(camera_pos) * CFrame.Angles(0, -camera_rotation.X, 0) * CFrame.Angles(camera_rotation.Y, 0, 0)
else
-- reset camera position when not moving
player_camera.WorldCFrame = CFrame.new(Vector3.new(0, height_offset, 0) + root_part.Position) * CFrame.Angles(0, -camera_rotation.X, 0) * CFrame.Angles(camera_rotation.Y, 0, 0)
end
end
toggle_player(true)
current_camera.CFrame = player_camera.WorldCFrame
end
function setup_camera(enabled)
if enabled then
cam_connection = RunService.PreRender:Connect(update_camera)
root_connection = RunService.PostSimulation:Connect(function()
if humanoid.Health > 0 then
local camera_look_vector = root_part.Position + current_camera.CFrame.LookVector
root_part.CFrame = CFrame.new(root_part.Position, Vector3.new(camera_look_vector.X, root_part.Position.Y, camera_look_vector.Z))
end
humanoid.AutoRotate = false
end)
else
if cam_connection and root_connection then
toggle_player(false)
humanoid.AutoRotate = true
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
current_camera.CameraType = Enum.CameraType.Custom
cam_connection:Disconnect()
root_connection:Disconnect()
end
end
end
setup_camera(true)