Issue with a Camera Walking Animation

Hello! I’m new to and just getting back into scripting and I want to recreate the walking animation from SCP Containment Breach, but I ran into an issue after getting the tilt corrected. Whenever I stop walking, the camera’s position and orientation automatically get reset to its 0, 0, 0 positions, when in reality I would want the Camera’s position to pause right where it is once walking stops.

The video below shows what it looks like.


I’ve dabbled with solutions and searched a bit, but I have yet to find a good answer that was clear enough for me to understand. None of them have worked and I’m not sure where to go from here. Any assistance is appreciated.

(If anything in this post needs to be clarified on I’ll do my best to explain more, this is my first post after all)

Script:

local runService = game:GetService("RunService")
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")

function updateBobbleEffect()
	local currentTime = tick()

	local bobble1 = math.abs(math.cos(currentTime * math.pi * 1.5) * .4)
	local bobble2 = math.cos(currentTime * math.pi * -1.5) * .01

	if humanoid.MoveDirection.Magnitude > 0 then
		workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * CFrame.Angles(0, 0, bobble2)
		workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * CFrame.new(0, bobble1, 0)
	end
end

runService.RenderStepped:Connect(updateBobbleEffect)
3 Likes

Use the Humanoid.Running event instead as well to detect when the Character starts to move

local runService = game:GetService("RunService")
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")

function updateBobbleEffect()
	local currentTime = tick()

	local bobble1 = math.abs(math.cos(currentTime * math.pi * 1.5) * .4)
	local bobble2 = math.cos(currentTime * math.pi * -1.5) * .01

    humanoid.Running:Connect(function(Speed)
        if Speed > 0 then
	        workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * CFrame.Angles(0, 0, bobble2)
	 	    workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * CFrame.new(0, bobble1, 0)
        end
	end)
end

runService.RenderStepped:Connect(updateBobbleEffect)
1 Like

I pasted this into the script and it removed the animation completely, is there something I missed when pasting it in? The Output nor the Script Analysis say anything is wrong with the script.

In case you need the info, the script is in StarterCharacterScripts and is the only one there, too.

1 Like

Hm, maybe try this? I’ll add a couple of prints to debug this:

local runService = game:GetService("RunService")
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")

function updateBobbleEffect()
    print("Running")
	local currentTime = tick()

	local bobble1 = math.abs(math.cos(currentTime * math.pi * 1.5) * .4)
	local bobble2 = math.cos(currentTime * math.pi * -1.5) * .01

        if humanoid.WalkSpeed > 0 then
        print("This mate is running")
	    workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * CFrame.Angles(0, 0, bobble2)
	    workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * CFrame.new(0, bobble1, 0)
    else
        print("This mate is not running")
    end
end

runService.RenderStepped:Connect(updateBobbleEffect)

Another thing I noticed while rewatching the video, the animation seems to play in the “background” while the player isn’t moving, and when the player starts moving it will jerk to wherever the animation would be were it to have been continuing.

I’m gonna try messing around with tweens to see if this will fix the issue.

1 Like

Hmm try this:

local RunService = game:GetService("RunService")

local playerModel = script.Parent
local humanoid = playerModel:WaitForChild("Humanoid")

local function updateBobbleEffect()
	local now = tick()
	if humanoid.MoveDirection.Magnitude > 0 then
    	local velocity = humanoid.RootPart.Velocity
    	local bobble_X = math.cos(now * 9) / 5
		local bobble_Y = math.abs(math.sin(now * 12)) / 5

		local bobble = Vector3.new(bobble_X,bobble_Y,0) * math.min(1, velocity.Magnitude /     humanoid.WalkSpeed)
    	  humanoid.CameraOffset = humanoid.CameraOffset:lerp(bobble,.25)
      end
   end
   RunService.RenderStepped:Connect(updateBobbleEffect)

Put a Localscript in StarterPlayer > StarterCharacterScripts.

Hope this helps and I think It works because tried this earlier.

1 Like

I came back to this issue after over a year and managed to figure it out!

The issue with the animation not pausing and resuming at the same point was the reliance on tick() and its relationship with the cosines. I solved this by making my own value with a NumberValue. I would have it add a very small amount every frame, mimicking the way tick() operated. The difference was that now this was something I could manipulate with scripts, so I simply halted the addition when the player wasn’t moving.

Secondly, another issue was the camera snapping back to its regular position when the player wasn’t moving. This was because I was only manipulating the camera when the player was moving. If I was still using tick(), this would mean that the animation would continue to play without movement, but because I pause the NumberValue’s addition when still, this solved itself.

One quirk was that I could control how fast the animation would play by changing the number increase every frame for the NumberValue. The closest I have right now to the original is 0.04, but if I wanted to make a running animation I could simply change it to 0.05 or 0.06.

Here’s the original script that I changed up a little:

local runService = game:GetService("RunService")
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")
local currentTime

function updateBobbleEffect()
	currentTime = workspace.CurrentTime.Value
	
	local bobble1 = math.abs(math.cos(currentTime * math.pi * 1.5) * .4)
	local bobble2 = math.cos(currentTime * math.pi * -1.5) * .01

	workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * CFrame.Angles(0, 0, bobble2)
	workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * CFrame.new(0, bobble1, 0)
end

runService.RenderStepped:Connect(updateBobbleEffect)

And here’s the new script that changes a NumberValue placed in the workspace:

local Time = workspace.CurrentTime

local RunService = game:GetService("RunService")

local playerModel = script.Parent
local humanoid = playerModel:WaitForChild("Humanoid")

while true do
	wait()
	if humanoid.MoveDirection.Magnitude > 0 then
		Time.Value = Time.Value + 0.035
		print(Time.Value)
	else
		print(Time.Value)
	end
end

(Both of these are LocalScripts placed in StarterCharacterScripts)

With my limited coding knowledge, I’m not sure if this is the most efficient way of doing things, but it works. So I guess I’ll live with it.

1 Like