Why does my Custom Camera script not work?

I am trying to create a custom first person camera and this script seems to not be working. When I run it the Camera gets locked on I’m pretty sure the center (0,0,0) in the workspace and is stuck there.

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()

local Camera = game.Workspace.CurrentCamera

local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

local CurrentPos
local NextPos
local Difference

local function Setup()
	-- Set initial camera cframe
	CurrentPos = HumanoidRootPart.Position
	Camera.CFrame = CFrame.new(CurrentPos,CurrentPos)
end

local function Update()
	-- Update camera cframe as position of HumanoidRootPart changes
	if CurrentPos and Character then
		NextPos = HumanoidRootPart.Position
		Difference = NextPos - CurrentPos
		CurrentPos = NextPos
		
		Camera.CFrame = Camera.CFrame + Difference
	end
end


Player.CharacterAdded:Connect(Setup)
game:GetService("RunService"):BindToRenderStep("Camera",Enum.RenderPriority.Camera.Value,Update)

You are waiting for the character before setting up your connection to Player.CharacterAdded. I would say you can test it by resetting your character and the camera now moves, but you never reassign the Character or HumanoidRootPart variables in your Setup function.

Just don’t wait for the character to be added when you set it at the beginning of the script, and the CharacterAdded event will fire on its own.

--[[ line 2

local Character = Player.Character or Player.CharacterAdded:Wait()

local Camera = game.Workspace.CurrentCamera

local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

-- change it to this ]]

local Character

local Camera = game.Workspace.CurrentCamera

local HumanoidRootPart



--[[ line 12

local function Setup()
	-- Set initial camera cframe
	CurrentPos = HumanoidRootPart.Position
	Camera.CFrame = CFrame.new(CurrentPos,CurrentPos)
end

-- change it to this ]]

local function Setup(char)
	-- Set initial camera cframe
	Character = char
	HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

	CurrentPos = HumanoidRootPart.Position
	Camera.CFrame = CFrame.new(CurrentPos)
end

Everything else should stay the same.

I’m pretty sure changing the Camera’s properties requires you to change it’s CameraType to Enum.CameraType.Scriptable first, except from that follow what @goldenstein64 says to do.

1 Like

So that worked, but there is one more thing. When I try calling these functions from a module script in the Setup function the output prints correctly, but the transparency doesn’t change.

Module Script:

local module = {}

function module.HideHats(Char)
	for _,v in pairs(Char:GetDescendants()) do
		if v:IsA("Accessory") then
			v:WaitForChild("Handle").LocalTransparencyModifier = 1

		end
	end
	print("Hidden Hats")	
	return true
end

function module.HideBody(Char)
	for _,v in pairs(Char:GetChildren()) do
		if v:IsA("BasePart") then
			v.LocalTransparencyModifier = 1
		end
	end	
	print("Hidden Body")
	return true
end


return module

Setup:

local function Setup(Char)
	-- Set initial camera cframe
	Character = Char
	HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
	
	HideModule.HideHats(Character)
	HideModule.HideBody(Character)
	
	CurrentPos = HumanoidRootPart.Position
	Camera.CFrame = CFrame.new(CurrentPos) + Vector3.new(0,2,0)
end

The output prints “Hidden Hats” and “Hidden Body” but they aren’t ‘hidden’ because I can still see them.

You have to wait until the character’s appearance is loaded before setting their transparency to 1. Regardless of rig type. Very simple event connection in theory:

-- also has a Character argument if you care
Player.CharacterAppearanceLoaded:Connect(function(Char)
	HideModule.HideHats(Char)
	HideModule.HideBody(Char) -- oops
end)

local function Setup(Char)
	-- Set initial camera cframe
	Character = Char
	HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

	-- just take out the HideModule stuff I guess

	CurrentPos = HumanoidRootPart.Position
	Camera.CFrame = CFrame.new(CurrentPos) + Vector3.new(0,2,0)
end

You can also just hide everything in the character using a function like this:

function module.HideEverything(Char)
	for _,v in pairs(Char:GetDescendants()) do
		if v:IsA("BasePart") then
			v.LocalTransparencyModifier = 1
		end
	end
	print("Hidden Everything")
	return true
end

Your choice though obviously.

That is true if you are creating your own script in StarterPlayerScripts not called CameraScript. But if it is called that, then you don’t need to worry about the CameraType, since it replaces the module that decided the behavior behind each CameraType in the first place.

It’s good practice to call it something else though if you plan on using the other CameraTypes though.

My script is called CameraScript in StarterPlayerScripts

1 Like

So everything works except the hiding of the player still. I think I know why, but am not sure how to fix it. In the CharacterAppearanceLoaded function how can I define what Char is?

local Player = game.Players.LocalPlayer
local Character

local HideModule = require(script.HideModule)

local Camera = game.Workspace.CurrentCamera
Camera.CameraType = Enum.CameraType.Scriptable

local HumanoidRootPart

local CurrentPos
local NextPos
local Difference

Player.CharacterAppearanceLoaded:Connect(function(Char)
	HideModule.HideLocalPlayer(Char)
end)

local function Setup(Char)
	-- Set initial camera cframe
	Character = Char
	HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
	
	CurrentPos = HumanoidRootPart.Position
	Camera.CFrame = CFrame.new(CurrentPos) + Vector3.new(0,2,0)
end

local function Update()
	-- Update camera cframe as position of HumanoidRootPart changes
	if CurrentPos and Character then
		NextPos = HumanoidRootPart.Position
		Difference = NextPos - CurrentPos
		CurrentPos = NextPos
		
		Camera.CFrame = Camera.CFrame + Difference
	end
end


Player.CharacterAdded:Connect(Setup)
game:GetService("RunService"):BindToRenderStep("Camera",Enum.RenderPriority.Camera.Value,Update)

Module:

local module = {}

function module.HideLocalPlayer(Char)
	for _,v in pairs(Char:GetDescendants()) do
		if v:IsA("BasePart") then
			v.LocalTransparencyModifier = 1
		end
	end
	print("Hidden Player")
	return true
end


return module

EDIT: I just realized Char is a parameter of CharacterAppearanceLoaded but it still doesnt work for some reason.

1 Like

I fixed it by putting the CharacterAppearanceLoaded function inside of Setup

EDIT: Broke when I tested it again

1 Like

It is almost as if it just skips over the function I added a print inside of it and it does not print it.

You’re probably getting thwarted by a couple of things.

CharacterAppearanceLoaded may not be firing when you’re testing in studio, if your avatar’s appearance has already loaded by the time CharacterAdded fires. One thing you could do in CharacterAdded is check Player:HasAppearanceLoaded(), but be warned, this can return true before your character’s body parts are actually parented to the character Model and ready to be made invisible, so…

The more robust way is to forget about appearance loaded and just loop over whatever parts are there at CharacterAdded time (if any) and connect up a Character.DescendantAdded listener to hide any additional parts as they are added to the character. This will even take care of accessories and tools you add during gameplay, so you’ll need to make exceptions for anything you add that you actually want to see.

Secondly, if you continue adding code to this script, and something yields above where you connect to CharacterAdded (even a single wait()), it’s possible that you’ll be connecting the CharacterAdded listener after it fires, so it will never catch the event for your initial spawn-in. You can make it more robust by doing something like this:

    if Player.Character then
        Setup(Player.Character)
    end
    Player.CharacterAdded:Connect(Setup)

Notice that the connection to CharacterAdded is not in an else block. You don’t want to conditionally connect to it, because it should always be connecting to handle respawns of your character.

Thank you, I got it to work on a Local Server test and in game, but for some reason it doesn’t work in studio. Other than the studio problem it works and I have no problem testing on Local Server instead of studio.