Camera type and subject not changing

  1. What do you want to achieve?
    When the player presses a button, I want the camera to switch from being scriptable and set to a part to custom (default) and being on the new model the player will spawn as.

  2. What is the issue?
    The rest of the code appears to work except for the camera being set. *There are no errors in the console. *

  3. What solutions have you tried so far?
    I’ve watched guides and endlessly scrolled the developer forums and yet I cannot find anything useful.

  4. Extra details
    I have the code that manages cameras in a module Script called “GuiHandler” in ReplicatedStorage that is called by scripts on the client. This is the function that manages it:

-- Set up camera
function guiHandler.setCam(playerCam,camPart)
	playerCam.CameraType = Enum.CameraType.Scriptable
	playerCam.CFrame = camPart.CFrame
	print(script.Name.. ": Player camera set")
end

This works for everything I need it to, but I’m putting it here in case it is a cause of the issue. On to what I think is more directly related somehow, when you press a spawn button, it fires a remoteEvent called “SpawnPlayer” and this code runs in a script in ServerScriptService. It basically just morphs the character:

remotes.SpawnPlayer.OnServerEvent:Connect(function(player,item)
	print("Test1")
	-- Perform data checks
	if typeof(item) ~= "Instance" then warn(script.Name.. ": Invalid input type. Try again.") return end
	
	-- Get in-game objects
	local model = game.ServerStorage.Operators:FindFirstChild(item.Name)
	local oldModel = player.Character
	local newModel = model:Clone()
	local spawnPoints = game.Workspace.SpawnPoints
	local parts = {spawnPoints.Spawn1, spawnPoints.Spawn2,spawnPoints.Spawn3,spawnPoints.Spawn4}
	local target = parts[math.random(#parts)]
	
	-- Set model properties
	newModel.Name = player.Name
	player.Character = newModel
	newModel.Parent = game.Workspace
	
	-- Copy StarterCharacterScripts
	for _, object in ipairs(game.StarterPlayer.StarterCharacterScripts:GetChildren()) do -- this just copies all the scripts from startercharacterscripts, you can do this with player scripts too.
		local newObject = object:Clone()
		newObject.Parent = newModel
	end
	
	-- Spawn player and destroy old model
	newModel:SetPrimaryPartCFrame(target.CFrame)
	oldModel:Destroy()
	remotes.SpawnPlayer:FireClient(player,newModel)
	print("Test2")
end)

You’ll notice there’s no camera changing stuff here. Knowing that you can only change the player’s camera client-side (as far as I am aware) I have it fire the client through the same remoteEvent after. I saw that the camera type being scriptable (as set by the GuiHandler) could cause issues, so rather than calling it I wrote the same code but with custom (this is on the same script that also initially fires the RemoteEvent:

game.ReplicatedStorage.Remotes.SpawnPlayer.OnClientEvent:Connect(function(operatorModel)
    print("Test3")
	local camera = workspace.Camera
	camera.CameraType = Enum.CameraType.Custom
	camera.CameraSubject = operatorModel.Humanoid
end)

Using prints, I’ve narrowed the issue down to the code above. It gets to “Test2” and “Test3” never prints to show the code ran. The code in the serverScript does fire the remoteEvent but for some reason the above code never runs. Going into the server-side view when testing I can see that it does spawn the model as well. Another notable thing is that the GUIs I have on the player’s screen go away (they are set to invisible by default and ResetOnSpawn is enabled, so that’s a possible explanation if it counts as respawning?)

The final thing I will point out here is that if I am in testing mode and manually change my camera to Custom, it will switch from the camera part that it is set to into this, which is closer to what I want but still not on the model right:


I can move the camera around the point it’s at like you would a normal character which is what I am trying to do but it is not actually on the model (Yes, I’m aware it’s in the ground that’s unrelated)

Try replacing workspace.Camera with workspace.CurrentCamera in this section:

game.ReplicatedStorage.Remotes.SpawnPlayer.OnClientEvent:Connect(function(operatorModel)
	local camera = workspace.Camera
	camera.CameraType = Enum.CameraType.Custom
	camera.CameraSubject = operatorModel.Humanoid
end)
1 Like

Unfortunately, that did not work.

I just realized I forgot to show where I put the prints (I tried them as I was making the post and never actually showed it that’s my fault) I’ll be editing the post in a second to include the print statements and where it gets to

Where is the LocalScript located? My only guess is that the .OnClientEvent isn’t connected to the RemoteEvent before the server script fires it.

1 Like

The local script is located in “StarterGui” under a button that’s in a viewport frame which is also under some folders and screenguis. I don’t know if that would cause any issues.
image
image

Also, if it is relevant here - The viewport Frame along with the button and script are copied multiple times by another script for each object in a folder in my ServerStorage. I do not believe that is causing any issues though since when clicked it sends the script’s parent which will have the name of the object it’s trying to get which is used by the script to find the right model (as shown by the fact it spawns the correct model when pressed)

Is the SpawnScript local script responsible for both the button behaviour and the camera manipulation? If it is responsible for both, then you could try waiting for the .OnClientEvent after FireServer().

Here is an example of what I mean by that:

local spawnRemoteEvent = game.ReplicatedStorage.Remotes.SpawnPlayer

spawnButton.MouseButton1Click:Connect(function()
	spawnRemoteEvent:FireServer(whatever your arguments are here)
	spawnRemoteEvent.OnClientEvent:Once(function(operatorModel)
		local camera = workspace.CurrentCamera
		camera.CameraType = Enum.CameraType.Custom
		camera.CameraSubject = operatorModel.Humanoid
	end)
end)

Though I will admit, this solution is a bit hacky (if it even works). If possible, I would recommend using a RemoteFunction instead for the client to invoke and get the operatorModel as a return value.

1 Like

The SpawnScript is responsible for both yes

Unfortunately, the same thing happens (It never triggered Test3 which I moved under the :Once thing)

I will look into using a remoteFunction they’ve just always been a bit confusing to me despite the documentation

Edit: Using a remoteFunction and a bit of somebody’s guide here I think I did what you meant- but the bug persists.

SpawnScript:

local player = game:GetService("Players").LocalPlayer

script.Parent.MouseButton1Click:Connect(function()
	local operator = game.ReplicatedStorage.Remotes.SpawnPlayer:InvokeServer(script.Parent)
	local camera = workspace.CurrentCamera
	camera.CameraType = Enum.CameraType.Custom
	camera.CameraSubject = operator.Humanoid
end)

OperatorMenuScript (spawning portion):

remotes.SpawnPlayer.OnServerInvoke = function(player,item)
	print("Test1")
	-- Perform data checks
	if typeof(item) ~= "Instance" then warn(script.Name.. ": Invalid input type. Try again.") return end
	
	-- Get in-game objects
	local model = game.ServerStorage.Operators:FindFirstChild(item.Name)
	local oldModel = player.Character
	local newModel = model:Clone()
	local spawnPoints = game.Workspace.SpawnPoints
	local parts = {spawnPoints.Spawn1, spawnPoints.Spawn2,spawnPoints.Spawn3,spawnPoints.Spawn4}
	local target = parts[math.random(#parts)]
	
	-- Set model properties
	newModel.Name = player.Name
	player.Character = newModel
	newModel.Parent = game.Workspace
	
	-- Copy StarterCharacterScripts
	for _, object in ipairs(game.StarterPlayer.StarterCharacterScripts:GetChildren()) do -- this just copies all the scripts from startercharacterscripts, you can do this with player scripts too.
		local newObject = object:Clone()
		newObject.Parent = newModel
	end
	
	-- Spawn player and destroy old model
	newModel:SetPrimaryPartCFrame(target.CFrame)
	oldModel:Destroy()
	print("Test2")
	return newModel
end