Manipulating Camera on Spawn

I’m working on an obby and when the player respawns, I want their camera to face forward to the next stage. When the player respawns, their character faces the right way, but my issue is that their camera faces the other direction.

I’ve tried to fix this using a RemoteEvent that fires to the client to manipulate the camera, but the code below causes the camera to position downwards.

local SetCamera = game.ReplicatedStorage:WaitForChild("SetCamera")
local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera

SetCamera.OnClientEvent:Connect(function()
	camera.CFrame = CFrame.new(camera.CFrame.Position, player.Character.HumanoidRootPart.CFrame.lookVector)
end)

Any help is appreciated, thanks!

2 Likes
local Player = game:GetService("Players").LocalPlayer
local Camera = workspace.CurrentCamera
Camera.CFrame = Player.Character.HumanoidRootPart.CFrame 
    * CFrame.Angles(math.rad(-15),0,0)

You can use the Player.CharacterAppearanceLoaded event on the client instead of using a remote as well.

8 Likes

Thanks, it worked. Do you mind giving a brief explanation of your solution? I’m very new to CFrames and Roblox Studio in general so any information helps.

Well, its a little weird because of how the camera core scripts seem to work. The rotation of the camera is changeable, while the distance from the character to the camera is maintained.

The CFrame we set uses the rotation portion of the humanoid root part (the core scripts discard the positional part), which sets the camera’s rotation to be that of the root part. Then, using CFrame.Angles(), we are decreasing the X axis of rotation by 15 degrees, which pitches the cameras rotation downward a little bit (to see over your character). Then, the core scripts kick in, and set the distance offset based on our current rotation, that offset being the current offset of your camera relative to the character.

3 Likes

Hi, I’m wondering where this might go? does it depend whether or not I have checkpoint saving setup already? Could I adapt the camera orientation into this?

local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local ObbyDataStore = DataStoreService:GetDataStore("ObbyDataStore")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local SkipStage = ReplicatedStorage:WaitForChild("SkipStage")
local ResetStage = ReplicatedStorage:WaitForChild("ResetStage")

local Checkpoints = workspace:WaitForChild("Checkpoints")
local inGameStartupPlayers = {}
local CurrentStage = {}
local TouchDb = {}

local ProductId = 0000000000 -- Change to your developer product id

local function NewCharacter(player, char)
	local TempCurrentStage = CurrentStage[player.UserId]
	if TempCurrentStage ~= nil then
		local TempCheckpoint = Checkpoints:FindFirstChild(TempCurrentStage)
		if TempCheckpoint ~= nil then
			repeat wait(0.1) until char.PrimaryPart ~= nil
			char:SetPrimaryPartCFrame(CFrame.new(TempCheckpoint.Position + Vector3.new(0, 6, 0)) * CFrame.Angles(0, math.rad(TempCheckpoint.Orientation.Y) + math.rad(90), 0))
		end
	end
end

local function NewPlayer(player)
	local success, stage = pcall(function()
		return (ObbyDataStore:GetAsync(player.UserId)) or 1
	end)

	CurrentStage[player.UserId] = stage

	local leaderstats = Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"
	local Stage = Instance.new("IntValue", leaderstats)
	Stage.Name = "Stage"
	Stage.Value = stage

	local TempChar = player.Character
	if TempChar ~= nil then
		NewCharacter(player, TempChar)
	end
	player.CharacterAdded:Connect(function(char)
		NewCharacter(player, char)
	end)
end

Players.PlayerAdded:Connect(function(player)
	if inGameStartupPlayers[player] == nil then
		NewPlayer(player)
	end
end)

Players.PlayerRemoving:Connect(function(player)
	local success = pcall(function()
		ObbyDataStore:SetAsync(player.UserId, CurrentStage[player.UserId])
	end)
	CurrentStage[player.UserId] = nil
end)

SkipStage.OnServerInvoke = function(player)
	local connection
	local leaderstats = player:FindFirstChild("leaderstats")
	if leaderstats ~= nil then
		local Stage = leaderstats:FindFirstChild("Stage")
		if Stage ~= nil then
			if #Checkpoints:GetChildren() ~= Stage.Value then
				local PurchaseResult = "Purchase Failed"
				connection = MarketplaceService.PromptProductPurchaseFinished:Connect(function(userId, productId, purchased)
					if player.UserId == userId and productId == ProductId then
						if purchased == true then
							PurchaseResult = "Success"
						end
					end
					connection:Disconnect()
				end)
				MarketplaceService:PromptProductPurchase(player, ProductId)
				repeat wait(0.1) until connection.Connected == false or Players:GetPlayerByUserId(player.UserId) == nil
				return PurchaseResult
			else
				return "You have reached the highest stage!"
			end
		end
	end
end

ResetStage.OnServerEvent:Connect(function(player)
	CurrentStage[player.UserId] = 0
	local TempLeaderstats = player:FindFirstChild("leaderstats")
	if TempLeaderstats ~= nil then
		local TempStage = TempLeaderstats:FindFirstChild("Stage")
		if TempStage ~= nil then
			TempStage.Value = 0
		end
	end     
	NewCharacter(player, player.Character)
end)

MarketplaceService.ProcessReceipt = function(recieptInfo)
	if recieptInfo.ProductId == ProductId then
		local player = Players:GetPlayerByUserId(recieptInfo.PlayerId)
		if player ~= nil then
			CurrentStage[player.UserId] = CurrentStage[player.UserId] + 1
			local leaderstats = player:FindFirstChild("leaderstats")
			if leaderstats ~= nil then
				local Stage = leaderstats:FindFirstChild("Stage")
				if Stage ~= nil then
					Stage.Value = CurrentStage[player.UserId]
				end
			end
			local TempChar = player.Character
			if TempChar ~= nil then
				NewCharacter(player, TempChar)
			end
			return Enum.ProductPurchaseDecision.PurchaseGranted
		end
	end
	return Enum.ProductPurchaseDecision.NotProcessedYet
end

for i,v in pairs(Checkpoints:GetChildren()) do
	local StageNum = tonumber(v.Name)
	v.Touched:Connect(function(hit)
		local char = hit.Parent
		if char ~= nil then
			local Humanoid = char:FindFirstChildOfClass("Humanoid")
			if Humanoid ~= nil and Humanoid.Health > 0 then
				local player = Players:GetPlayerFromCharacter(char)
				if player ~= nil and (TouchDb[player.UserId] or 0) + 1 <= os.time() then
					TouchDb[player.UserId] = os.time()
					local TempCurrentStage = CurrentStage[player.UserId]
					if TempCurrentStage == StageNum - 1 then
						CurrentStage[player.UserId] = StageNum
						local TempLeaderstats = player:FindFirstChild("leaderstats")
						if TempLeaderstats ~= nil then
							local TempStage = TempLeaderstats:FindFirstChild("Stage")
							if TempStage ~= nil then
								TempStage.Value = StageNum
							end
						end
					end
				end
			end
		end
	end)
end

inGameStartupPlayers = Players:GetPlayers()
for i,v in pairs(inGameStartupPlayers) do
	spawn(function()
		NewPlayer(v)
	end)
end

game:BindToClose(function()
	for i,v in pairs(Players:GetPlayers()) do
		ObbyDataStore:SetAsync(v.UserId, CurrentStage[v.UserId])
	end
	wait(1)
end)

inGameStartupPlayers = {}