Script works in Studio, not in Roblox Player

I have a script that handles a player’s lives, gamemodes and other smaller features within my game. The script works perfectly fine in Roblox Studio, no problems there. When I load into the game from the site/app though, The UI is not hidden by default and when I start a new game/load my saved game it does not change. Strangely enough if I reset my character everything initializes normally and functions as intended afterward, just not when I join the game from the site/application. I’ve used printing for debugging and it doesn’t even seem to get to anything modifying the UI before it just seems to stop. Again, functions perfectly in the studio testing.


local function spinObject(object)
	local function onRenderStepped()
		object.CFrame = object.CFrame * CFrame.Angles(0, 0, 0.05)
	end

	local connection = RunService.RenderStepped:Connect(onRenderStepped)

	object.AncestryChanged:Connect(function(_, parent)
		if not parent then
			connection:Disconnect()
		end
	end)
end

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local StartGameEvent = ReplicatedStorage:WaitForChild("StandardRun")
local PracticeModeEvent = ReplicatedStorage:WaitForChild("PracticeMode")
local GameOverEvent = ReplicatedStorage:WaitForChild("GameOver")
local EndGameEvent = ReplicatedStorage:WaitForChild("EndGameEvent")
local ResetGameEvent = ReplicatedStorage:WaitForChild("ResetGame")
local PlayerLoseLifeEvent = game.ReplicatedStorage:WaitForChild("PlayerLoseLife")

local player = game.Players.LocalPlayer
local gui = script.Parent
local TextLabel


local defaultLivesMapping = {
	StandardRun = 10,--for testing purposes as I still need to reset data when you game over
}

local currentGameMode = "StandardRun"

local remainingLives = player:WaitForChild("RemainingLives")

local gameStarted = false

local function updateTextLabel()
	if TextLabel then
		if gameStarted then
			if currentGameMode == "PracticeMode" then
				TextLabel.Parent.Visible = false -- Hide the lives UI in PracticeMode
			else
				TextLabel.Text = remainingLives.Value
				if TextLabel.Parent and TextLabel.Parent.LivesText then
					TextLabel.Parent.LivesText.Text = "Lives"
				end
				TextLabel.Parent.Visible = true
			end
		else
			TextLabel.Text = "X"
			TextLabel.Parent.Visible = false
			TextLabel.Parent.Parent.Reset.TextButton.Visible = false
		end
	end
end

player.PlayerGui.ChildAdded:Connect(function(child)
	if child.Name == "Hud" then
		TextLabel = child.Lives:WaitForChild("LivesValue")
		updateTextLabel()
	end
end)

local function shakeTextLabel()
	if TextLabel and gameStarted then
		local originalPosition = TextLabel.Position
		local originalTextColor = TextLabel.TextColor3
		local duration = 0.4
		local intensity = 7

		local startTime = tick()
		local function updateShake()
			local currentTime = tick() - startTime
			if currentTime <= duration then
				local offsetX = math.random() * intensity * 2 - intensity
				local offsetY = math.random() * intensity * 2 - intensity
				TextLabel.Position = UDim2.new(originalPosition.X.Scale, originalPosition.X.Offset + offsetX, originalPosition.Y.Scale, originalPosition.Y.Offset + offsetY)
				TextLabel.TextColor3 = Color3.new(1, 0.313725, 0.313725)
				TextLabel.Text = "-1"
			else
				TextLabel.Position = originalPosition
				TextLabel.TextColor3 = originalTextColor
				TextLabel.Text = remainingLives.Value
				shakeConnection:Disconnect()
				PlayerLoseLifeEvent:FireServer(remainingLives.Value)
			end
		end
		shakeConnection = game:GetService("RunService").Heartbeat:Connect(updateShake)
	end
end

local function handleLifeCoinInteraction(coin)
	if gameStarted then
		remainingLives.Value = remainingLives.Value + 1
		updateTextLabel()
		coin.Attachment.Sparkle:Stop()
		game.Soundscape:PlayLocalSound(game.Soundscape.LifeUp)
		coin.Transparency, coin.Icon.Transparency, coin.Icon2.Transparency = 0.9, 0.9, 0.9
		coin.Attachment.PointLight.Enabled, coin.Highlight.Enabled = false, false
		coin.Attachment.CollectionParticle.Enabled = true
		wait(0.1)
		coin.Attachment.CollectionParticle.Enabled = false
		PlayerLoseLifeEvent:FireServer(remainingLives.Value)
	end
end

local function connectLifeCoinTouched(coin)
	local touchedConnection

	touchedConnection = coin.Touched:Connect(function(hit)
		local character = hit.Parent
		local humanoid = character:FindFirstChild("Humanoid")

		if humanoid and gameStarted and player == game.Players:GetPlayerFromCharacter(character) then
			if touchedConnection then
				touchedConnection:Disconnect()
			else
				print("Error: touchedConnection is nil")
			end

			handleLifeCoinInteraction(coin)
		end
	end)
end

local function resetLifeCoins()
	if gameStarted then
		for _, coin in pairs(game.Workspace.LifeCoins:GetChildren()) do
			connectLifeCoinTouched(coin)
			spawn(function() spinObject(coin) end)
		end
	end
end

resetLifeCoins()

player.CharacterAdded:Connect(function(character)
	local humanoid = character:WaitForChild("Humanoid")

	humanoid.Died:Connect(function()
		if gameStarted then
			if currentGameMode ~= "PracticeMode" then
				if remainingLives.Value > 1 then
					remainingLives.Value = remainingLives.Value - 1
					game.Soundscape:PlayLocalSound(game.Soundscape.Die)
					shakeTextLabel()
				else
					remainingLives.Value = defaultLivesMapping[currentGameMode]
					if GameOverEvent then
						GameOverEvent:FireServer(player)
					end

					local lifeCoinsFolder = game.Workspace:FindFirstChild("LifeCoins")
					if lifeCoinsFolder then
						lifeCoinsFolder:Destroy()
					end

					if currentGameMode == "StandardRun" then
						game.ReplicatedStorage.LifeCoins:Clone().Parent = game.Workspace
					end

					wait(1)
					resetLifeCoins()
				end
			else
				-- Play "Die" sound when the player dies in practice mode
				game.Soundscape:PlayLocalSound(game.Soundscape.Die)
			end

			updateTextLabel()
		end
	end)
end)

StartGameEvent.OnClientEvent:Connect(function()
	currentGameMode = "StandardRun"
	remainingLives.Value = defaultLivesMapping[currentGameMode]
	gameStarted = true
	TextLabel.Parent.LivesText.Text = "Lives"
	player.PlayerGui.Hud.Reset.TextButton.Visible = true
	updateTextLabel()

	local lifeCoinsFolder = game.Workspace:FindFirstChild("LifeCoins")
	if lifeCoinsFolder then
		lifeCoinsFolder:Destroy()
	end

	game.ReplicatedStorage.LifeCoins:Clone().Parent = game.Workspace
	resetLifeCoins()
end)

PracticeModeEvent.OnClientEvent:Connect(function()
	currentGameMode = "PracticeMode"
	remainingLives.Value = 0 -- No restriction on lives
	gameStarted = true
	TextLabel.Parent.Visible = false -- Hide the Lives UI
	player.PlayerGui.Hud.Reset.TextButton.Visible = true -- Allow resetting the game

	local lifeCoinsFolder = game.Workspace:FindFirstChild("LifeCoins")
	if lifeCoinsFolder then
		lifeCoinsFolder:Destroy()
	end
end)

EndGameEvent.OnClientEvent:Connect(function()
	TextLabel.Parent.Visible = false
	game.Players.LocalPlayer.PlayerGui.Hud.Reset.TextButton.Visible = false
	player.PlayerGui.Hud.Reset.TextButton.Visible = false

	game.Soundscape:PlayLocalSound(game.Soundscape.Goal)

	if currentGameMode == "PracticeMode" then
		gameStarted = false
	end
end)

ResetGameEvent.OnClientEvent:Connect(function()
	remainingLives.Value = defaultLivesMapping[currentGameMode]
	gameStarted = false
	TextLabel.Parent.Visible = false
	player.PlayerGui.Hud.Reset.TextButton.Visible = false

	-- Handle LifeCoins reset
	local lifeCoinsFolder = game.Workspace:FindFirstChild("LifeCoins")
	if lifeCoinsFolder then
		lifeCoinsFolder:Destroy()
	end

	if currentGameMode == "StandardRun" then
		game.ReplicatedStorage.LifeCoins:Clone().Parent = game.Workspace
	end

	resetLifeCoins()

	-- Update the text label
	updateTextLabel()
end)

GameOverEvent.OnClientEvent:Connect(function()
	gameStarted = false
	TextLabel.Parent.Visible = false
	player.PlayerGui.Hud.Reset.TextButton.Visible = false

	-- Handle tools reset
	for _, tool in ipairs(player.Backpack:GetChildren()) do
		if tool:IsA("Tool") then
			tool:Destroy()
		end
	end
	if player.Character:FindFirstChildOfClass("Tool") then
		player.Character:FindFirstChildOfClass("Tool"):Destroy()
	end
end)


-- Assuming the rest of your client-side script is already set up as provided

PlayerLoseLifeEvent.OnClientEvent:Connect(function(loadedRemainingLives)
	-- Update UI or game state with remainingLives
	print("Remaining Lives received on client:", loadedRemainingLives)

	-- Update the UI text label with the loaded remaining lives
	if TextLabel and gameStarted then
		if currentGameMode == "PracticeMode" then
			TextLabel.Parent.Visible = false -- Hide the lives UI in PracticeMode
		else
			TextLabel.Text = loadedRemainingLives
			TextLabel.Parent.LivesText.Text = "Lives"
			TextLabel.Parent.Visible = true
		end
	end
end)

-- Connect to the CheckPointReached event from ReplicatedStorage
local CheckPointReachedEvent = ReplicatedStorage:WaitForChild("CheckPointReached")
CheckPointReachedEvent.OnClientEvent:Connect(function()
	-- Print remainingLives value
	print("Reached checkpoint! Remaining Lives:", remainingLives.Value)

	-- Fire PlayerLoseLifeEvent with remainingLives value
	PlayerLoseLifeEvent:FireServer(remainingLives.Value)
end)

You can try using .CharacterAppearanceLoaded to ensure everything about the character loads before your script executes.

1 Like