Trouble With CameraBob Script

So, I made a sprint script where when you Sprint your camera bobs.
My Issue is that whenever I walk AFTER sprinting my Camera continues to bob unless I completely stop.

To fix it, I’m trying to use Local Function(), but that’s not working either.
Also I’m getting no errors if you’re wondering.

local Character = plr.Character or plr.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")

local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local Camera = workspace.CurrentCamera
local DeltaTimeOffset = 1 / 60 
local BobbingOffset = CFrame.new()
local RunAnim = Humanoid:LoadAnimation(script:WaitForChild("Sprint"))
local JumpAnim = Humanoid:LoadAnimation(script:WaitForChild("Jump"))
local Running = script:WaitForChild("IsRunning").Value
local CamBob = script:WaitForChild("Bobbing").Value
Running = false
local notMoving = true
local isOnGround = true
local Jumped = false
local originalSpeed = Humanoid.WalkSpeed
local db = true
local db2 = true
local db3 = true
CamBob = false
local lastPosition = Character.PrimaryPart.Position

----------------- Changeable ---------------------

local RunButton = Enum.KeyCode.LeftShift -- Change this to the key you want for running
local newSpeed = 25 -- Speed you want while running
local DefaultFieldOfView = 70 -- Default FOV
local SprintFieldOfView = 78 -- Running FOV
local MobileButton = plr.PlayerGui.MobileGUI.MobileButtons.RunButton -- Location of the button
local MaxStamina = 200  -- Max amount of stamina
local StaminaReductionRate = 10 -- How much the stamina goes down every 1 second while running
local StaminaRecoveryRate = 5 -- How much the stamina goes back up every 1 second while not running
local MinStaminaToRun = 15 -- Minimum amount of stamina required to run
local StaminaValue = script.Stamina.Value -- Where to locate the Stamina Value

--------------------------------------------------

StaminaValue = MaxStamina
Camera.FieldOfView = DefaultFieldOfView

-------------------
local function CameraBob()
	RunService.RenderStepped:Connect(function(DeltaTime)
		local Offset = DeltaTime / DeltaTimeOffset
		local IsMoving = Humanoid.MoveDirection.Magnitude > 0.01
		local CurrentCameraPosition = Camera.CFrame * BobbingOffset:Inverse()
		-- for example: CFrame - BobbingOffset

		local ZDirection = -math.round(Humanoid.MoveDirection:Dot(Camera.CFrame.RightVector))
		BobbingOffset = BobbingOffset:Lerp(
			CFrame.Angles(
				IsMoving and 
					math.rad(math.sin(time() * 10)) / 1.2 * Offset or
					math.rad(math.sin(time())) / 50 * Offset,

				IsMoving and 
					math.rad(math.sin(time() * 10)) / 1.2 * Offset or 
					math.rad(math.cos(time())) / 50 * Offset,

				math.rad(ZDirection * 1) * Offset
			),
			0.1
		)

		Camera.CFrame = Camera.CFrame * BobbingOffset
	end)
end
------------------------------------------


local function Run()
	if Running == false and CamBob == false and isOnGround == true and StaminaValue >= MinStaminaToRun and script.RunEnabled.Value == true then
		Running = true
		CamBob = true
		RunAnim:Play()
		Humanoid.WalkSpeed = newSpeed
		CameraBob(true)
		local goal1 = { FieldOfView = SprintFieldOfView }
		local info1 = TweenInfo.new(0.5)
		local tween1 = TweenService:Create(Camera, info1, goal1)
		tween1:Play()
	end
end

local function Stop()
	if Running == true and CamBob == true then
		Running = false
		CamBob = false
		RunAnim:Stop()
		Humanoid.WalkSpeed = originalSpeed
		CameraBob(false)
		local goal2 = { FieldOfView = DefaultFieldOfView }
		local info2 = TweenInfo.new(1)
		local tween2 = TweenService:Create(Camera, info2, goal2)
		tween2:Play()
	end
end

MobileButton.MouseButton1Click:Connect(function()
	if Running == false then
		Run()
	elseif Running == true then
		Stop()
	end
end)

UIS.InputBegan:Connect(function(input, isTyping)
	if isTyping then return end
	if input.KeyCode == RunButton then
		Run()
	end
end)

UIS.InputEnded:Connect(function(input)
	if input.KeyCode == RunButton then
		Stop()
	end
end)

RunService.Heartbeat:Connect(function() 
	notMoving = Humanoid.MoveDirection.Magnitude == 0
	if notMoving then
		Stop()
	end

	if Running == true and Humanoid:GetState() == Enum.HumanoidStateType.Physics or Humanoid:GetState() == Enum.HumanoidStateType.Seated or Humanoid:GetState() == Enum.HumanoidStateType.Swimming or Humanoid:GetState() == Enum.HumanoidStateType.Climbing or Humanoid:GetState() == Enum.HumanoidStateType.Dead then
		Stop()
	end

	if Running == true and Humanoid:GetState() == Enum.HumanoidStateType.Jumping then
		Jumped = true
		RunAnim:Stop()
		JumpAnim:Play()
	end

	if Running == true and Jumped == true and Humanoid:GetState() == Enum.HumanoidStateType.Landed then
		Jumped = false
		RunAnim:Play()
	end
	
	if Running == true and db2 == true then
		if StaminaValue >= MinStaminaToRun then
			db2 = false
			StaminaValue = StaminaValue - StaminaReductionRate
			wait(1)
			db2 = true
		end
	end

	if Running == false and db3 == true then
		if StaminaValue < MaxStamina then
			db3 = false
			StaminaValue = math.min(StaminaValue + StaminaRecoveryRate, MaxStamina)
			wait(1)
			db3 = true
		end
	end


	if StaminaValue < MinStaminaToRun then
		Stop()
	end
	
	if Running == true and script.RunEnabled.Value == false then
		Stop()
	end
	
	isOnGround = Humanoid.FloorMaterial ~= Enum.Material.Air

	if isOnGround and Running == true and db == true then
		db = false
		local dust = game.ReplicatedStorage.Fx.Dust:Clone()
		dust.Position = Character:WaitForChild("HumanoidRootPart").Position + Vector3.new(0, -2.5, 0)
		dust.Parent = workspace.Fx
		dust.Name = "RunDust"
		dust.Attachment.Dust:Emit(1)
		game.Debris:AddItem(dust, 2.5)
		wait(0.15)
		db = true
	end

	if Running == true then
		for i = 1, math.random(1,2) do
			local rp = Instance.new("Part", workspace.Fx)
			rp.Anchored = true
			rp.CanCollide = false
			rp.Transparency = 0.8
			rp.Name = "RunParticle"
			rp.Material = Enum.Material.SmoothPlastic
			rp.CanQuery = false
			rp.Size = Vector3.new(0.05, 0.05, math.random(2.5, 3.5))
			local colorRandom = math.random(1,3)
			if colorRandom == 1 then
				rp.Color = Color3.fromRGB(107, 107, 107)
			elseif colorRandom == 2 then
				rp.Color = Color3.fromRGB(175, 175, 175)
			elseif colorRandom == 3 then
				rp.Color = Color3.fromRGB(148, 148, 148)
			end
			local dirCFrame = CFrame.new(lastPosition, Character.PrimaryPart.Position)
			rp.CFrame = dirCFrame * CFrame.new(math.random(-25, 25)/10,math.random(-2.5, 2.5), math.random(-2, 2))
			game.Debris:AddItem(rp, 0.75)
			TweenService:Create(rp,TweenInfo.new(0.75), {Transparency = 1, Size = Vector3.new(0, 0, 0), CFrame = rp.CFrame * CFrame.new (0,0,math.random(2.5, 4))}):Play()
		end
	end
	lastPosition = Character.PrimaryPart.Position
end)```
Untested re-wright

I don’t have your other scripts so, this is best guess.
This may not totally work but, has a whole lot of good scripting in it.
If it isn’t working maybe take the time to go over it for tips…

local plr = game.Players.LocalPlayer
local Character = plr.Character or plr.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")

local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local Camera = workspace.CurrentCamera

local DeltaTimeOffset = 1 / 60
local BobbingOffset = CFrame.new()
local RunAnim = Humanoid:LoadAnimation(script:WaitForChild("Sprint"))
local JumpAnim = Humanoid:LoadAnimation(script:WaitForChild("Jump"))
local Running = script:WaitForChild("IsRunning").Value
local CamBob = script:WaitForChild("Bobbing").Value
local isOnGround = true
local Jumped = false
local originalSpeed = Humanoid.WalkSpeed
local lastPosition = Character.PrimaryPart.Position

-- Configurable variables
local RunButton = Enum.KeyCode.LeftShift
local newSpeed = 25
local DefaultFieldOfView = 70
local SprintFieldOfView = 78
local MobileButton = plr.PlayerGui.MobileGUI.MobileButtons.RunButton
local MaxStamina = 200
local StaminaReductionRate = 10
local StaminaRecoveryRate = 5
local MinStaminaToRun = 15
local StaminaValue = script.Stamina.Value

-- Initialize
StaminaValue = MaxStamina
Camera.FieldOfView = DefaultFieldOfView

local function CameraBob(isActive)
	if isActive then
		RunService.RenderStepped:Connect(function(DeltaTime)
			local Offset = DeltaTime / DeltaTimeOffset
			local IsMoving = Humanoid.MoveDirection.Magnitude > 0.01
			local ZDirection = -math.round(Humanoid.MoveDirection:Dot(Camera.CFrame.RightVector))

			BobbingOffset = BobbingOffset:Lerp(
				CFrame.Angles(
					IsMoving and math.rad(math.sin(time() * 10)) / 1.2 * Offset or 0,
					IsMoving and math.rad(math.sin(time() * 10)) / 1.2 * Offset or 0,
					math.rad(ZDirection * 1) * Offset
				),
				0.1
			)

			Camera.CFrame = Camera.CFrame * BobbingOffset
		end)
	else
		-- Reset Camera bobbing
		BobbingOffset = CFrame.new()
		Camera.CFrame = Camera.CFrame * BobbingOffset
	end
end

local function Run()
	if not Running and CamBob == false and isOnGround and StaminaValue >= MinStaminaToRun and script.RunEnabled.Value then
		Running = true
		CamBob = true
		RunAnim:Play()
		Humanoid.WalkSpeed = newSpeed
		CameraBob(true)

		local tween = TweenService:Create(Camera, TweenInfo.new(0.5), { FieldOfView = SprintFieldOfView })
		tween:Play()
	end
end

local function Stop()
	if Running then
		Running = false
		CamBob = false
		RunAnim:Stop()
		Humanoid.WalkSpeed = originalSpeed
		CameraBob(false)

		local tween = TweenService:Create(Camera, TweenInfo.new(1), { FieldOfView = DefaultFieldOfView })
		tween:Play()
	end
end

MobileButton.MouseButton1Click:Connect(function()
	if Running then
		Stop()
	else
		Run()
	end
end)

UIS.InputBegan:Connect(function(input, isTyping)
	if isTyping then return end
	if input.KeyCode == RunButton then
		Run()
	end
end)

UIS.InputEnded:Connect(function(input)
	if input.KeyCode == RunButton then
		Stop()
	end
end)

RunService.Heartbeat:Connect(function()
	local isMoving = Humanoid.MoveDirection.Magnitude > 0.01
	isOnGround = Humanoid.FloorMaterial ~= Enum.Material.Air

	if not isMoving or not isOnGround or Humanoid:GetState() == Enum.HumanoidStateType.Jumping or 
		Humanoid:GetState() == Enum.HumanoidStateType.Physics or Humanoid:GetState() == Enum.HumanoidStateType.Seated or
		Humanoid:GetState() == Enum.HumanoidStateType.Swimming or Humanoid:GetState() == Enum.HumanoidStateType.Climbing or
		Humanoid:GetState() == Enum.HumanoidStateType.Dead then
		Stop()
	end

	if Running and Humanoid:GetState() == Enum.HumanoidStateType.Jumping then
		Jumped = true
		RunAnim:Stop()
		JumpAnim:Play()
	end

	if Running and Jumped and Humanoid:GetState() == Enum.HumanoidStateType.Landed then
		Jumped = false
		RunAnim:Play()
	end

	if Running and StaminaValue >= MinStaminaToRun then
		StaminaValue = StaminaValue - StaminaReductionRate
	else
		Stop()
	end

	if not Running and StaminaValue < MaxStamina then
		StaminaValue = math.min(StaminaValue + StaminaRecoveryRate, MaxStamina)
	end

	if Running and isOnGround then
		local dust = game.ReplicatedStorage.Fx.Dust:Clone()
		dust.Position = Character:WaitForChild("HumanoidRootPart").Position + Vector3.new(0, -2.5, 0)
		dust.Parent = workspace.Fx
		dust.Name = "RunDust"
		dust.Attachment.Dust:Emit(1)
		game.Debris:AddItem(dust, 2.5)
	end

	if Running then
		for i = 1, math.random(1, 2) do
			local rp = Instance.new("Part", workspace.Fx)
			rp.Anchored = true
			rp.CanCollide = false
			rp.Transparency = 0.8
			rp.Name = "RunParticle"
			rp.Material = Enum.Material.SmoothPlastic
			rp.Size = Vector3.new(0.05, 0.05, math.random(2.5, 3.5))
			rp.Color = Color3.fromRGB(math.random(107, 175), math.random(107, 175), math.random(107, 175))
			rp.CFrame = CFrame.new(lastPosition, Character.PrimaryPart.Position) * CFrame.new(math.random(-25, 25) / 10, math.random(-2.5, 2.5), math.random(-2, 2))
			game.Debris:AddItem(rp, 0.75)
			TweenService:Create(rp, TweenInfo.new(0.75), { Transparency = 1, Size = Vector3.new(0, 0, 0), CFrame = rp.CFrame * CFrame.new(0, 0, math.random(2.5, 4)) }):Play()
		end
	end

	lastPosition = Character.PrimaryPart.Position
end)
isMoving Script

A good way to tell if they are moving.
Just a way to maybe set up a trigger to control bob on and off better.

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

local isMoving = false

game:GetService("RunService").RenderStepped:Connect(function()
    isMoving = humanoid.MoveDirection.Magnitude > 0
end)
Camera Bob

This is one of my scripts. Feel free to use it for whatever.
There are a lot of settings. You’ll have to play around with it
if you want it to bob differently. Ran a test on this before posting.
This one uses HumanoidRootPart.Velocity.magnitude
I would wright that differently if I was to do this now.
(using the isMoving Script style)

--Camera Bob. Client Script in StarterCharacterScripts

local Workspace = game:GetService("Workspace")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

local player = game:GetService("Players").LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local HumanoidRootPart = player.Character:WaitForChild("HumanoidRootPart")
local Mouse = player:GetMouse()
local Camera = Workspace.CurrentCamera

local TouchEnabled = UserInputService.TouchEnabled
UserInputService.MouseIconEnabled = false

local function lerp(v1, v2, t)
	return v1 + (v2 - v1) * t
end

local angleX, x, y, tilt, vX, vY, sX, sY = 0, 0, 0, 0, 0, 0, 10, 10

RunService.RenderStepped:Connect(function(dt)
	dt *= 60
	local velocity = HumanoidRootPart.Velocity.magnitude
	local randomX = math.random(10, 15)
	local randomY = math.random(5, 10)

	if dt <= 2 then
		vX = lerp(vX, math.cos(tick() * 0.5 * randomX) * (math.random(5, 20) / 200) * dt, 0.05 * dt)
		vY = lerp(vY, math.cos(tick() * 0.5 * randomY) * (math.random(2, 10) / 200) * dt, 0.05 * dt)
	else vX, vY = 0, 0
	end

	Camera.CFrame *= CFrame.Angles(0, 0, math.rad(angleX))
		* CFrame.Angles(math.rad(math.clamp(x * dt, -0.15, 0.15)), math.rad(math.clamp(y * dt, -0.5, 0.5)), tilt)
		* CFrame.Angles(math.rad(vX), math.rad(vY), math.rad(vY * 10))
	tilt = math.clamp(
		lerp(tilt, -Camera.CFrame:VectorToObjectSpace((HumanoidRootPart and HumanoidRootPart.Velocity or Vector3.new())
			/ math.max(player.Character.Humanoid.WalkSpeed, 0.01)).X * 0.05, 0.1 * dt), -0.05, 0.05
	)

	if not TouchEnabled and dt < 2 then
		angleX = lerp(angleX, math.clamp(UserInputService:GetMouseDelta().X / dt * 0.15, -2.5, 2.5), 0.25 * dt)
	end x = lerp(x, math.sin(tick() * sX) / 5 * math.min(1, sY / 10), 0.25 * dt)

	if velocity > 1 then y = lerp(y, math.cos(tick() * 0.5 * math.floor(sX)) * (sX / 200), 0.25 * dt)
	else y = lerp(y, 0, 0.05 * dt)
	end

	if velocity > 12 then sX, sY = 20, 18
	elseif velocity > 0.1 then sX, sY = 12, 14
	else sY = 0
	end
end)
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.