As part of a sliding mechanic, I’m interpolating the Humanoid’s CameraOffset property over time.
Whenever I playtest, both in Studio and in the live servers, the sliding mechanic seems to be working as intended. Nevertheless, another member of the development team, warned me that, when playing in live servers sometimes the camera doesn’t lower at all. He has showed me videos of this, and whenever I’ve added logs, they confirmed that, despite the CameraOffset property updating properly, for some reason the camera’s height seems to remain more or less consistent (it barely moves).
I’ve also confirm through logs that the function is being called and with the correct arguments.
Previously, I was using TweenService for this, but, in an attempt to solve the issue, I’ve moved to a custom RenderStepped implementation, which apparently changed nothing.
I’ve tried looking at similar posts but I haven’t found any instances of the camera offset not offsetting a player’s camera.
The script runs in a client RunContext so it’s not about that. There is also no other scripts writing to the Humanoid’s CharacterOffset property. Some other details I’ve confirmed through logs and tests:
- CameraType is set Custom
- CameraSubject is set to the Humanoid
- The Humanoid has RootPart set.
I’ve also been told that whenever the slide camera offset stops working, the keybind I’ve set below for testing purposes also stops working, which seems to confirm that the issue is not with the solver itself, but with the CameraOffset property, something is causing it to stop affecting the camera’s Position.
For reference the player.CameraMode is set to LockFirstPerson. I’ve moved the entire camera offset solver onto a different module for clarity when I was debugging, you can check it out below:
--SERVICES--
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
--VARIABLES--
local player = Players.LocalPlayer :: Player
local ACTION_ID = "CameraOffsetController"
local PRIORITY = Enum.RenderPriority.Camera.Value - 1
local CameraOffsetController = {}
--PRIVATE FUNCTIONS--
local function easeSineWave(t: number): number
return -0.5 * (math.cos(t * math.pi) - 1)
end
local function interpolateCameraOffset(humanoid: Humanoid, goal: Vector3, fadeDuration: number): ()
local startingOffset = humanoid.CameraOffset
local timer = 0
RunService:BindToRenderStep(ACTION_ID, PRIORITY, function(dt: number): ()
timer += dt
local camera = workspace.CurrentCamera
if not camera or humanoid.Parent == nil then
RunService:UnbindFromRenderStep(ACTION_ID)
return
elseif timer >= fadeDuration then
RunService:UnbindFromRenderStep(ACTION_ID)
humanoid.CameraOffset = goal
print("ANIMATION FINISHED")
return
end
local t = timer / fadeDuration
local alpha = math.min(1, easeSineWave(t))
local offset = startingOffset:Lerp(goal, alpha)
humanoid.CameraOffset = offset
end)
end
--PUBLIC FUNCTIONS--
function CameraOffsetController.offsetCamera(offset: Vector3, fadeDuration: number?): ()
local character = player.Character
local humanoid = character and character:FindFirstChildWhichIsA("Humanoid")
if not humanoid then
return
end
RunService:UnbindFromRenderStep(ACTION_ID)
if not fadeDuration or fadeDuration <= 0 then
humanoid.CameraOffset = offset
return
end
interpolateCameraOffset(humanoid, offset, fadeDuration)
end
--INITIALIZATION--
function CameraOffsetController.init(): ()
--test keybind that also does nothing whenever the CameraOffset property bugs
local ContextActionService = game:GetService("ContextActionService")
ContextActionService:BindAction("TestOffset", function(_, state: Enum.UserInputState)
if state ~= Enum.UserInputState.Begin then
return
end
CameraOffsetController.offsetCamera(Vector3.zero)
CameraOffsetController.offsetCamera(-2 * Vector3.yAxis)
task.delay(0.5, CameraOffsetController.offsetCamera, Vector3.zero)
end, false, Enum.KeyCode.E)
end
return table.freeze(CameraOffsetController)