Help with Cutscene

Hey,

I am making smooth cutscene. I used before parts as a camera positions but I have to use like 50 different Parts in one cutscene. So I tried to set camera CFrame to player head’s CFrame. It is almost working but there are 2 problems:

  1. shake
  2. camera sometimes looks different way than it should

Here are the code and video where you can see the problem. Yeah, yeah… there are many different posts about this but I try to make smooth cutscenes and I do things a bit differently.

Code:

local camera = game.Workspace.CurrentCamera
local cutscenesFolder = game.Workspace:FindFirstChild("Cutscenes").Chase
local tweenService = game:GetService("TweenService")
local runService = game:GetService("RunService")
local function startCutscene(duration)
	local character = player.Character
	if not character then return end

	local head = character:FindFirstChild("Head")
	local humanoid = character:FindFirstChildOfClass("Humanoid")

	if not (head and humanoid and camera) then return end


	local startTime = tick() 
	local offsetDistance = -1 

	local connection
	connection = runService.RenderStepped:Connect(function()
		local elapsedTime = tick() - startTime
		if elapsedTime >= duration then
			connection:Disconnect()
			camera.CameraType = Enum.CameraType.Custom
			humanoid.CameraOffset = Vector3.new(0, 0, -1)
			return
		end

		
		local headCFrame = head.CFrame
		local newCameraCFrame = headCFrame * CFrame.new(0, 0, offsetDistance)

		camera.CFrame = head.CFrame--CFrame.lookAt(newCameraCFrame.Position, headCFrame.Position + headCFrame.LookVector)

		
		humanoid.CameraOffset = Vector3.new(0, 0, -1)
	end)
end
local hposes = {
	cutscenesFolder.Hpos,
	cutscenesFolder.Hpos2,
	cutscenesFolder.Hpos3,
	cutscenesFolder.Hpos4,
	cutscenesFolder.Hpos5,
	cutscenesFolder.Hpos6,
	cutscenesFolder.Hpos7
}
local function startHRP()
	tweenService:Create(player.Character.HumanoidRootPart, TweenInfo.new(0.1, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut), {CFrame = hposes[1].CFrame}):Play()
	wait(0.1)
	tweenService:Create(player.Character.HumanoidRootPart, TweenInfo.new(2.9, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut), {CFrame = hposes[2].CFrame}):Play()
	wait(7.6)
	tweenService:Create(player.Character.HumanoidRootPart, TweenInfo.new(0.3, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut), {CFrame = hposes[3].CFrame}):Play()
	wait(0.57)
	tweenService:Create(player.Character.HumanoidRootPart, TweenInfo.new(0.73, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut), {CFrame = hposes[4].CFrame}):Play()
	wait(2.73)
	tweenService:Create(player.Character.HumanoidRootPart, TweenInfo.new(6, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut), {CFrame = hposes[5].CFrame}):Play()
	wait(17)
	tweenService:Create(player.Character.HumanoidRootPart, TweenInfo.new(0.2, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut), {CFrame = hposes[6].CFrame}):Play()
	wait(5.4)
	tweenService:Create(player.Character.HumanoidRootPart, TweenInfo.new(0.6, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut), {CFrame = hposes[7].CFrame}):Play()
	wait(0.6)
end
fol.Chaseblocks.colliderfirst.Touched:Connect(function(Hit)
	camera.CameraType = Enum.CameraType.Scriptable
	game.Players.LocalPlayer:WaitForChild("CutsceneLock").Value = true
	wait()
	player.Character.Humanoid.WalkSpeed = 0
	wait()
	player.Character.HumanoidRootPart.Anchored = true
	player.Character.Humanoid.AutoRotate = false
	task.spawn(function()
		startCutscene(34)
	end)
	startHRP()
	camera.CameraType = Enum.CameraType.Custom
	game.Players.LocalPlayer:WaitForChild("CutsceneLock").Value = false
	player.Character.Humanoid.WalkSpeed = 20
	player.Character.HumanoidRootPart.Anchored = false
	player.Character.Humanoid.AutoRotate = true
end)

Video:

I would like to get help asap. I am still trying to fix this by myself but I haven’t found any solutions yet.

1 Like

if you intended the tween to be played sequentially (wait for each tween to complete and then play the next tween)

now you are doing
tween1:Play()
wait(tween1Duration)
tween2:Play()

because of inaccuracy of tween duration and wait time, i think it might play tween2 before tween1 completed. this will make it “shake”

try
tween1:Play()
tween1.Completed:Wait()
tween2:Play()

2 Likes

no. The problem isn’t that. It works normally. The problem is in the startCutscene() function. The camera itself is the problem. But of course it can be possible that tweens are causing the shake effect.

I set the code ignore the HumanoidRootPart tweening but it did nothing. It’s still doing weird shaking and camera is looking at weird directions sometimes.

I have tried to fix it but I can’t solve it by myself.

i’m quite confused of what the camera is doing. because you seem to be only tweening the cframe of player hrp.

i’ll try to explain your code logic

this seems to be a local script. because we see it uses game.Players.LocalPlayer
when we touch the ‘chase blocks’, we will move the camera by scriptable function that comes in startCutscene()
we try to do something to ‘disable the player movements’

calling startCutscene() in parallel, during that time, we make the camera behind the head (those lines are conflicting each other, i can only think that you want it behind the head)

calling startHRP() to move the player hrp. notice it only tween the root, it doesn’t tween the head. so why does the camera look up and down in the video? does it mean the whole player body is now rotated up and down. will roblox try to pull the player back to the upright position?

1 Like

The player is animated in that cutscene so that’s why the head is moving. However, sometimes the camera is just shaking and sometimes goes behind the player’s head. It should show like you see in real life. You know, like from your face, not behind your head.

I’ll explain quickly:

  1. Yes, it is local script
  2. This code is meant to move camera AND humanoidrootpart at the same time because in the cutscene you walk so that’s why humanoidrootpart needs to be moved. Otherwise you just walk and you don’t move. That startCutscene is meant to move the camera and keep it always on player head’s CFrame and make sure the camera is also looking from player’s face, not inside player’s head or behind the head. That’s why I use humanoid Cameraoffset. Normally outside cutscene Cameraoffset is Vector3.new(0, 0, -1).

The problem is how to get rid of that random shake and camera sometimes looking up or down.
Drawing

have you got some Hpos (cutscene locator) that look up and down? (check their rotations)


They are normal. I also made code ignore that HRP mover function so the body should not move and it shouldn’t affect to the camera. Still didn’t do anything. Player is just moving without actually moving.

then there is some other script that moved the player. or you failed to disable the user input so it moved by the user ?

Player should work normally. I’m pretty sure there is no script that makes player head move like that. The animation also looks normal. Here you can see where player’s head should face.

don’t know if these work as intended.
conflict between camera set cframe and humanoid camera offset?

another check, if the camera follow hrp instead of the head, will it shake?

another suggestion, use CFrame:Lerp() to smooth out the camera movement

1 Like

I tried those and when I use HRP CFrames instead of using Head’s CFrames, it works normally. When using head, it’s still shaking and looking up or down. However, now it’s less shaking than before.

I made a part that follows player head’s CFrame and it looks normal:

1 Like

The character model might be colliding with something since you are tweening the character’s hrp. The part at the bottom of the stage might be too low. The camera shake may be the collisions. The camera will have a bit of a shake when doing this since the character is not “floating”.

It’s no longer shaking. The head colliding may cause the camera looking up or down. I am trying to make it so it doesn’t affect to the camera

It is kinda working when I set part’s CFrame to player’s head CFrame using while loop and then set camera’s CFrame to part’s CFrame. However, the part doesn’t move smoothly so it looks bad when watching the cutscene.

Something like this might work. you will need to fix the variables, maybe add a seperate set of look at locations, and adjust player walk speed as needed. And add adjustment the viewpoint of the camera : player.CameraMode = Enum.CameraMode LockFirstPerson or Classic.

local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local Controls = require(LocalPlayer.PlayerScripts.PlayerModule):GetControls()

local character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local camera = workspace.CurrentCamera
local cutscenesFolder = workspace:WaitForChild("Cutscenes"):WaitForChild("Chase")

-- Define positions for movement
local hposList = {
	cutscenesFolder:WaitForChild("Hpos"),
	cutscenesFolder:WaitForChild("Hpos2"),
	cutscenesFolder:WaitForChild("Hpos3"),
	cutscenesFolder:WaitForChild("Hpos4"),
	cutscenesFolder:WaitForChild("Hpos5"),
	cutscenesFolder:WaitForChild("Hpos6"),
	cutscenesFolder:WaitForChild("Hpos7"),
}

local currentStep = 1

-- Disable Player Controls
local function disablePlayerControls()
	Controls:Disable()
end

-- Enable Player Controls
local function enablePlayerControls()
	Controls:Enable()
end

-- Move Player and Adjust Camera
local function moveToNextPosition()
	if currentStep > #hposList then
		enablePlayerControls()
		return
	end

	local nextPos = hposList[currentStep].Position
	humanoid:MoveTo(nextPos)

	-- Wait until the player reaches the target position
	humanoid.MoveToFinished:Wait()
	print("Reached: ", nextPos)

	currentStep += 1

	if currentStep <= #hposList then
		-- Make the camera look at the next point
		local lookAtPos = hposList[currentStep].Position
		camera.CFrame = CFrame.new(camera.CFrame.Position, lookAtPos)

		-- Move to the next position
		moveToNextPosition()
	else
		enablePlayerControls() -- Re-enable player controls after movement
	end
end

-- Trigger Cutscene When Touching Collider
workspace.Chaseblocks.colliderfirst.Touched:Once(function(hit)
	if hit.Parent == character then
		disablePlayerControls()
		currentStep = 1
		moveToNextPosition()
	end
end)
1 Like

Ummm… I am looking for a smooth cutscene. It requires cool and smooth head movement. If I just use HRP positions, it doesn’t look cool. Feels like you’re a robot who only looks at one direction (HRP positions are in a stright line). I provided earlier a video where you can see the head movement in 3rd perpective. I need that kind of movement but in a smooth way. That part doesn’t move smoothly so that’s why I kind of cannot use that. The animation should feel and look same what you can do without cutscene by yourself inside the game.

But I appreciate you want to help me.

Hey,

We haven’t found solution yet. I need the solution asap. I may sound a bit rude but this is important and I have tried so many ways to fix it but still no solutions founded. :sob: :weary:

possible fix:

local function startCutscene(duration)
	local character = player.Character
	if not character then return end

	local head = character:FindFirstChild("Head")
	local humanoid = character:FindFirstChildOfClass("Humanoid")

	if not (head and humanoid and camera) then return end

	local startTime = tick()
	local offsetDistance = -1 

	local connection
	connection = runService.RenderStepped:Connect(function(deltaTime)
		local elapsedTime = tick() - startTime
		if elapsedTime >= duration then
			connection:Disconnect()
			camera.CameraType = Enum.CameraType.Custom
			humanoid.CameraOffset = Vector3.new(0, 0, -1)
			return
		end

		local headCFrame = head.CFrame
		local targetCFrame = headCFrame * CFrame.new(0, 0, offsetDistance)
		
		-- Lerp the camera position for smooth movement
		camera.CFrame = camera.CFrame:Lerp(targetCFrame, deltaTime * 10) 

		humanoid.CameraOffset = Vector3.new(0, 0, -1)
	end)
end

fix the Camera Facing the Wrong Way

camera.CFrame = head.CFrame
--and
camera.CFrame = CFrame.lookAt(targetCFrame.Position, headCFrame.Position + headCFrame.LookVector)

also maybe do this:

humanoid.AutoRotate = false