Camera manipulation without the character?

I’m trying to make a deploy when the player joins, and respawns, so they have to click ‘Deploy’ when they want their character to load. CharacterAutoLoads is set to false, and to make it so the GUI works without the character I had to use this:

player:LoadCharacter()
player.Character = nil

Problem is that stops the camera from working :confused:

local target = workspace.StarterCamera
local camera = workspace.CurrentCamera
camera.CameraType = Enum.CameraType.Scriptable
camera.CameraSubject = target

local currentAngle = 0
     
camera.CoordinateFrame = CFrame.new(target.Position) * CFrame.Angles(0, 0, 0) * CFrame.new(0, 0, -6)

So the camera is basically positioned inside of a room, but when I test this in studio, the camera is just set to wherever I was during studio play, and I can scroll around, zoom in/out, etc.
Even bigger problem is when I load an actual game, the GUI doesn’t even load at all.

How it should look:

How it looks:

1 Like

You should be setting the camera’s mode to Scriptable first so you don’t need to force it (by setting CoordinateFrame every frame, which can make things more difficult).

The GUI doesn’t load because the GUIs in StarterGui only load when the player spawns - you’ll need to manually put them into the player.

Ok set it to scriptable. If the guis dont load, then how come when I click play solo on studio they load perfectly, but not in an online game server?

Probably it has to do with play solo’s way of handling servers since it uses the client as the server when playing.

Yeah, definitely don’t do this. I enabled a flag last week to move all of our camera control to Lua, and it was exactly places doing things like this that caused us to have to roll it back, and I’m having to put in some safeguards for things I never knew devs did. What you want to do is manually parent your GUI to the player’s PlayerGui (from StarterGui, ReplicatedStorage or ReplicatedFirst, etc).

Do not do any of the following if you want a future-proof game:
Create and immediately destroy the player character.
Create and place the character far away.
Create the player character and delete its humanoid.

Roblox camera and character control scripts watch for the player character (and the Humanoid within) to be added and replicated to the client. These scripts get references to parts of the character and humanoid, which are then invalid if the character is destroyed unexpectedly (without transitioning to Humanoid.Died, or removing normally and firing Player.CharacterRemoving). Depending on exactly when you destroy players’ characters, you might also be causing everyones’ clients to load their packages unnecessarily. If you keep the character around, and keep it hidden somewhere, this can also cause camera issues if you’re not manually setting the camera subject and focus correctly each frame.

6 Likes

TL;DR - If you have a game where you don’t use the player character, but you spawn it and hide it or destroy() it, you’re going to want to refactor that very soon.

4 Likes

What’s changing is that we’re in the process of moving all of our camera scripts and control scripts from C++ to Lua, which ultimately favors developer flexibility and customization. All of the camera and character controller playerscripts are getting a big refactor as part of this, and one of the goal is to make nice, clean, well-organized modules that not only work more efficiently, but serve as example code and the starting point for custom playerscripts.

The playerscripts are going to be efficient and clean code if they rely on expected and supported use of the Roblox character. The playerscripts could be a mess if they have conditional branches making exceptions for all known or possible unconventional usage patterns. So, for example, I think it’s reasonable for a Roblox-supplied player character controller to assume that if LocalPlayer.CharacterAdded fires, that the player’s character is spawning and a character controller module should be activated and assigned to control it. And if said character’s humanoid dies, or CharacterRemoving fires, the control script should handle this too. But setting Player.Character = nil, or character.Parent = nil, or character:Destroy() or character.Humanoid:Destroy(), etc. while the control scripts are in the process of initializing? I think the scripts should guard against dereferencing nil, but not go as far as bloating the code with strategies for gracefully adapting to any possible scenario.

If a game is not going to use a default Roblox player character (avatar or StarterPlayerCharacter) at all, I think it’s perfectly reasonable for the supported best practice to be setting Players.CharacterAutoLoads = false, and not calling LoadCharacter. As a developer trying to make a game that performs well, you don’t want to incur the cost of loading character packages (meshes, textures, animations, etc.), instantiating or executing character controller code you don’t intend to use or even want running.

That said, most games are going to weather the changes without incident. We had the Lua camera flag on last week, and found a few issues that are bugs in our existing code, but overall there were just a handful of reported breakages and the ones that were not our obvious bugs were in games that were doing something we don’t really consider a supported practice, such as deleting a character’s Humanoid, or updating the camera CFrame or Focus from somewhere other than a function bound to RenderStepped (e.g. while true do UpdateCamera() wait() end ). Games that do things like this are not guaranteed to remain working, and I think in most cases the developers know deep down that sweeping the player character under the bed is not the correct way to make a character-less game.

3 Likes