Help on little nightmares camera system!

Hello everyone! I am in need of some help.

So as the title suggests, i am trying to make a little nigthmares inspired camera system, the correct term for it would “Camera Rail.” I have the script for it, and it works, Kind of…

Whats the problem?

See the script follows the rail for a short while, and works just as intended, but then, it stops when its not even near the end! I have tried everything and nothing on the dev forum has helped, i even used chatgpt and it didnt work!

Here’s my script:

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local camera = game.Workspace.CurrentCamera
local rail = workspace:FindFirstChild("CameraRail") 

local railPoints = {}
for _, part in ipairs(rail:GetChildren()) do
	table.insert(railPoints, part.Position)
end

table.sort(railPoints, function(a, b)
	return a.Z < b.Z 
end)

local TweenService = game:GetService("TweenService")
local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)

local function followRail()
	local closestPoint = railPoints[1]
	local characterPosition = character.PrimaryPart.Position

	for _, point in ipairs(railPoints) do
		if (characterPosition - point).Magnitude < (characterPosition - closestPoint).Magnitude then
			closestPoint = point
		end
	end

	if closestPoint then
		camera.CameraType = Enum.CameraType.Scriptable
		local goalCFrame = CFrame.new(closestPoint + Vector3.new(0, 5, 0), characterPosition)

		local tween = TweenService:Create(camera, tweenInfo, {CFrame = goalCFrame})
		tween:Play()
	else
		warn("No closest point found on the rail!")
	end
end

game:GetService("RunService").RenderStepped:Connect(followRail)

More Context to the script:
The Rail Itself:


The parts in the rail:

What i want to acieve:

  • A smooth transition between parts without skipping or snapping backwards.
  • To stop only while it’s at the end part and not at some random part.
  • To follow the rail as is, because some parts in my rail go up and down, front and back, and i want it to follow the whole rail.
    *Keep following the player no matter what, as in keep looking at the player as it moves along the rail.

How can i achieve it?
That’s where you guys come in! I don’t want full fledged scripts, i simply would like some advice or some Assitance on it, i don’t have much robux so i cannot hire anybody, but please help! Thanks in advance.

if you have anymore questions about the game my discord is dizzytwisted

2 Likes

I think the issue is you move the camera to the nearest part once, then after the tween ends, nothing else happens. Try to do it in a repeated function instead, where it moves the camera every time the tween ends:

local function moveCamera()
	for _, point in ipairs(railPoints) do
		if (characterPosition - point).Magnitude < (characterPosition - closestPoint).Magnitude then
			closestPoint = point
		end
	end

	if closestPoint then
		camera.CameraType = Enum.CameraType.Scriptable
		local goalCFrame = CFrame.new(closestPoint + Vector3.new(0, 5, 0), characterPosition)

		local tween = TweenService:Create(camera, tweenInfo, {CFrame = goalCFrame})
		tween:Play()

		tween.Completed:Wait()
	else
		warn("No closest point found on the rail!")
	end
end

for i, point in ipairs(railPoints) do
	if i ~= #rail:GetChildren() then
		moveCamera()
	end
end

I’ve applied your script to mine and it still seems to stop at a certain point. Let me show you what it’s doing"

(Ignore the first bit, Im trying to get it to work properly)

But as you can see it’s still stopping at some random point that isn’t the end, when there more rail to move to… im so confused because it doesn’t give me any sort of error or warning.

--LocalScript in StarterPlayerScripts 
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local TweenService = game:GetService("TweenService")
local rail = workspace:WaitForChild("CameraRail") 
local camera = workspace.CurrentCamera

local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0, false, 0)
local railPoints = {}

for i = 1, #rail:GetChildren() do
	local part = rail:FindFirstChild("Part" .. string.format("%02d", i))
	if part then table.insert(railPoints, part.Position) end
end

local function moveCamera()
	for _, point in ipairs(railPoints) do
		camera.CameraType = Enum.CameraType.Scriptable
		local goalCFrame = CFrame.new(point + Vector3.new(0, 5, 0), point + Vector3.new(0, 0, 90)) --facing direction
		local tween = TweenService:Create(camera, tweenInfo, {CFrame = goalCFrame})
		tween:Play() task.wait(0.3) --play around with this for smoothness
	end
end

moveCamera()

--points are named Part01 Part02 Part03 exc.. No "guessing" where to go next.
--Part001 Part002 would be; part=rail:FindFirstChild("Part"..string.format("%03d",i))

But wouldnt this take a lot of work? i have alot of parts in my camera rail, so surely there is a better way of going about this right?

tab is your friend … in this case. 100% solid for sure path to follow. (worth the time)
Tested very well … also used 10 studs apart.

Yes, However! There will be instances where i want to deactivate the script, right, would it still go to the nearest part the chartacter is near once the script reactivates or will it stop working?

You would have to modify it. Just a version I was playing with could add more for sure.
Try a small one like 15 parts … for a test, 10 studs apart.

So i’ve just tested it, and it doesn’t follow the player? It simply glitches along the rail i have made… I don’t understand?

my script originally is supposed to look at the player as it progresses. the player moves with the rail and vise versa.

odd … works fine for me. It isn’t following the player however. path.wmv (583.1 KB)
I guess I missed “*Keep following the player no matter what.”

What do you mean by “follow the player” keep looking at them?
You may have to work with it a bit …

script
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local TweenService = game:GetService("TweenService")
local rail = workspace:WaitForChild("CameraRail") 
local camera = workspace.CurrentCamera

local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0, false, 0)
local railPoints = {}

for i = 1, #rail:GetChildren() do
	local part = rail:FindFirstChild("Part" .. string.format("%02d", i))
	if part then table.insert(railPoints, part.Position) end
end

local function moveCamera()
	for _, point in ipairs(railPoints) do
		if not character.PrimaryPart then return end
		camera.CameraType = Enum.CameraType.Scriptable
		local goalCFrame = CFrame.new(point + Vector3.new(0, 5, 0), character.PrimaryPart.Position) 
		local tween = TweenService:Create(camera, tweenInfo, {CFrame = goalCFrame})
		tween:Play() 
		task.wait(0.33)
	end
end

moveCamera()

No reason this shouldn’t be working as it is on my screen … It just follows the path of blocks size 1,1,1 spaced 10 studs apart. Now it keep looking at the player.

Possibly create your block in order … it sure isn’t going to read them in the order you see them, unless you made them that way or placed them in that way. Why I went for something with an order to it.

Here is a test showing what I was talking about, good luck.

task.wait(1)
local folder = game.Workspace:WaitForChild("CameraRail")
local children = folder:GetChildren()

table.sort(children, function(a, b) return a.Name < b.Name end)

for _, child in ipairs(children) do
	print(child.Name)
end

My bad it will pull them out of order but this should fix that … like you were using.

Yeah, I’ve tried it but unfortunately it doesn’t seem to work. I don’t know what else to do.