How do I make this camera script work?

Hi everyone!

Goal

I hope you’re well. I’m trying to work on optimizing the current camera system by making it into a ModuleScript rather than individual LocalScripts.

What’s the issue?

I am assuming since I use RenderStepped:Connect(), the ModuleScript interferes with the connection every time a new camera perspective is chosen. I’m not sure how to fix this. I would assume that that’s the problem.

Script

local GlobalCamera = {}

local CameraTypes = {
    Vector3.new(-50, 0, 0), -- Normal View
    Vector3.new(-50, 50, 0), -- Up View
    Vector3.new(-30, -5, 0) -- Death View
}

local Camera = workspace.CurrentCamera

local Character = game.Players.LocalPlayer.Character
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
Camera.CameraType = Enum.CameraType.Scriptable

function GlobalCamera.SetCamera(Choice)
    game:GetService("RunService").RenderStepped:Connect(function()
        Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)
    end)
end

return GlobalCamera

How can I structure this better so it disconnects the RenderStepped or something, please? I’m not really good at making anything related to RenderStepped if I’m honest, it could be a very simple solution.

I’ve also taken this part of the script:

    game:GetService("RunService").RenderStepped:Connect(function()
        Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)
    end)

From a very old project of mine, so there could be a better way to do it.

Thanks,
Aki

2 Likes

To Remove an RBXConnection you need to use the :Disconnect() function.
It can be triggered like this:

local Connection = nil
Connection = game:GetService("RunService").RenderStepped:Connect(function()
        Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)
        if <something happens> then
              Connection:Disconnect()
        end)
end)

Also a quick tip:
I see a lot of people doing this but it all depends on the person’s liking:
If you are making functions in a module use the : symbol.
Basically use dots only for module variables and double dots for functions. It’s just a practice to differentiate both when using a module script.

I hope the answer helps out. If you have any further questions feel free to reply.

2 Likes

Hi! Thank you for your tips and help! I’ve tried what you said. Now I have to click the button activating the function for every frame to work.

local GlobalCamera = {}

local CameraTypes = {
    Vector3.new(-50, 0, 0), -- Normal View
    Vector3.new(-50, 50, 0), -- Up View
    Vector3.new(-30, -5, 0) -- Death View
}

local Camera = workspace.CurrentCamera
local Connection = nil

local Character = game.Players.LocalPlayer.Character
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
Camera.CameraType = Enum.CameraType.Scriptable
local InitialChoice = nil

function GlobalCamera.SetCamera(Choice)
    if InitialChoice == nil then
        InitialChoice = Choice
    end
    Connection = game:GetService("RunService").RenderStepped:Connect(function()
        if InitialChoice ~= nil then
            Connection:Disconnect()
        end
        Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)
    end)
end

return GlobalCamera

I feel like this has to do with:

 if InitialChoice ~= nil then
            Connection:Disconnect()
        end

Not sure how else to structure it, though…

1 Like

One more thing. Keep those local items in the local script and place the line:

Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)

as a module function.
Then require the module and call the function from the localscript.
Also keep the CameraTypes table variable into the module as it would be easier to access the data from the module. It could count as seperate.
I would call that clean code and optimized.
Basically any events regarding RunService are kept in the localscript as ny code cn be ran later with them. As for changing local variables or object properties are done in modules. Think of it as the localscript holds the main parts of a script and the modules are the logical parts of a script.

1 Like
local GlobalCamera = {}

local CameraTypes = {
    Vector3.new(-50, 0, 0), -- Normal View
    Vector3.new(-50, 50, 0), -- Up View
    Vector3.new(-30, -5, 0) -- Death View
}

local Camera = workspace.CurrentCamera
local Connection = nil

local Character = game.Players.LocalPlayer.Character
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
Camera.CameraType = Enum.CameraType.Scriptable
local InitialChoice = nil
local Choice = nil

local function CameraSet()
    Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)
end

function GlobalCamera.SetCamera(Choice)
    if InitialChoice == nil then
        InitialChoice = Choice
    end
        if InitialChoice ~= nil then
            Connection:Disconnect()
        end
        CameraSet()
end

return GlobalCamera

Something like this?

1 Like

You will have a small issue. That would be that the :Disconnect() is supposed to be in the main localscript.
Make the InitialChoise condition in the localscript and replce the CameraSet() with Module:CameraSet().
Don’t forget to change:

local function CameraSet()
    Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)
end

to

function GlobalCamera:CameraSet()
    Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)
end

local mod = require(game:GetService("ReplicatedFirst").Modules.Camera)
local InitialChoice = nil
local Connection = nil

script.Parent.MouseButton1Down:Connect(function()
    Connection = game:GetService("RunService").RenderStepped:Connect(function()

        if InitialChoice == nil then
            InitialChoice = 1
        end
        if InitialChoice ~= nil then
            Connection:Disconnect()
        end
        mod.SetCamera(1)
    end)
end)

This is what I have in the LocalScript

local GlobalCamera = {}

local CameraTypes = {
    Vector3.new(-50, 0, 0), -- Normal View
    Vector3.new(-50, 50, 0), -- Up View
    Vector3.new(-30, -5, 0) -- Death View
}

local Camera = workspace.CurrentCamera
local Connection = nil

local Character = game.Players.LocalPlayer.Character
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
Camera.CameraType = Enum.CameraType.Scriptable
local Choice = nil

function GlobalCamera:CameraSet()
    Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)
end

return GlobalCamera

This is the ModuleScript

2 Likes

I am a bit unsure why you’d want to create a lot of renderstepped cases but ok. Still yes that’s what I would call optimized.

1 Like

Heh, I’m sorry if I’m causing you any confusion. I really don’t like handling anything related to RunService, though I’m trying it at the moment! I’ll update you with the results. :slight_smile:

3 Likes

Just disconnect the last event.

1 Like


?

local GlobalCamera = {}

local CameraTypes = {
    Vector3.new(-50, 0, 0), -- Normal View
    Vector3.new(-50, 50, 0), -- Up View
    Vector3.new(-30, -5, 0) -- Death View
}

local Camera = workspace.CurrentCamera
local Connection = nil

local Character = game.Players.LocalPlayer.Character
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
Camera.CameraType = Enum.CameraType.Scriptable

function GlobalCamera:CameraSet(Choice)
    Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)
end

return GlobalCamera

That’s odd, it shouldn’t be nil.

1 Like

Can you elaborate on what you mean exactly, please? I’m sorry if this sounds a bit annoying. I previously mentioned I’m not good at handling RunService or events in general. @_@

1 Like
local GlobalCamera = {}

local CameraTypes = {
	Vector3.new(-50, 0, 0), -- Normal View
	Vector3.new(-50, 50, 0), -- Up View
	Vector3.new(-30, -5, 0) -- Death View
}

local Camera = workspace.CurrentCamera

local Character = game.Players.LocalPlayer.Character
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
Camera.CameraType = Enum.CameraType.Scriptable

local LastConnection

function GlobalCamera.SetCamera(Choice)
	if LastConnection then
		LastConnection:Disconnect()
		LastConnection = nil
	end

	LastConnection = game:GetService("RunService").RenderStepped:Connect(function()
		Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(HumanoidRootPart.Position + CameraTypes[Choice], HumanoidRootPart.Position), 0.05)
	end)
end

return GlobalCamera
1 Like
function GlobalCamera:CameraSet(Choice)

May I see how you are calling this function? The localscript?

local InitialChoice = nil
local Connection = nil

script.Parent.MouseButton1Down:Connect(function()
    Connection = game:GetService("RunService").RenderStepped:Connect(function()

        if InitialChoice == nil then
            InitialChoice = 1
        end
        if InitialChoice ~= nil then
            Connection:Disconnect()
        end
        mod.CameraSet(1)
    end)
end)

I can’t do :, it forces me to do .
image

1 Like

Awesome! It worked amazingly! Thank you so much for the help! :))

(Thank you to @HighFoxyplayz11 aswell for the time!)

3 Likes

You should’ve used the CameraSet function as that was the one I used but whatever :smiley:.

2 Likes

Nevermind… I’m sorry for revoking your solution, though I spoke a bit too soon. The buttons were working completely fine but now when I load a map in, it’s only the sky that shows, I’m not sure why…

Edit:

I realized the problem. The camera is not following the player. Why’s that? Thanks

2 Likes

Small update (sorry for rapid replies)

I’ve disabled the Studio beta feature for the new camera system. It did fix it just a little bit but not by much.

As you can tell the camera is VERY offset from the HumanoidRootPart.

I ran this command in the console:
local mod = require(game:GetService("ReplicatedFirst").Modules.Camera) mod.SetCamera(2)

and it gave me the result of that footage above.

So, I noted 2 things.

  • The camera is REALLY off-centered from the character
  • The camera stops working when the player resets.

What do I do about it? Thanks

Update, I’ve got the solution from @deadalready! I just had to update the HumanoidRootPart on CharacterAdded. :slight_smile:

Thanks DGuy! <3

1 Like