Lives Incrementing Inconsistently

I have a game where, every round, a set of 5 obstacles is chosen, with each obstacle being harder than the last. You have 3 lives each round, but I’ve recently been having trouble with making the lives not go down multiple times on impact. It’s a bit more complicated than it might seem though.

I’ll define kill parts as these neon red objects that kill the player upon impact, and I’m defining water as an invisible layer under all the obstacles that also kills upon impact.

What works:

  • When the player touches the water, the lives only go down once. This is intentional.
  • The same thing happens with kill parts, it only goes down once. Again, intentional.

What doesn’t work:

  • When the player simultaneously touches water and a kill part (e.g. if they rub against a kill part while falling into the water), the player’s lives will go down by 2 increments. For instance, if the player’s life count is 3, it’ll go down to 1.
  • The server script in the respective heading.

Reproducing:

  • To reproduce, join the game and find an obstacle with kill parts (red & neon colored). Go to that side and rub against it while falling into the water. Your lives will likely decrease by 2.

Attempted (and failed) debounce script:
This is a script in ServerScriptService that attempts to rectify the issue with multiple lives. However, it doesn’t work at all. It doesn’t cause alternate problems, but it doesn’t solve the one at hand either. It does not produce any errors.

game.Players.PlayerAdded:Connect(function(player)
	local livesLeft = player:FindFirstChild("LivesLeft") -- IntValue stores in player for lives left

    local debounce = false
	livesLeft.Changed:Connect(function() -- when lives change
		if debounce == true then
			livesLeft.Value += 1 -- should reverse impact of double-decreasing by increasing only one unit, but this does not work
			debounce = false
		else
			debounce = true -- if the debounce is not already on, turn it on
			
			local triggers = { -- these are parts that should negate the debounce as these are your "start points"
				workspace.StartPart1,
				workspace.StartPart2,
				workspace.StartPart3,
				workspace.StartPart4,
				workspace.StartPart5,
				workspace.SpawnPart, -- in the lobby, in case your lives run out
			}
			
			for _, part in ipairs(triggers) do
				part.Touched:Connect(function(hit)
					if hit.Parent:FindFirstChildWhichIsA("Humanoid") then
						if game:GetService("Players"):GetPlayerFromCharacter(hit.Parent) == player then
							debounce = false -- if any of them are touched, and the player that touched them is the player of interest, then turn off the debounce so it resets it
						end
					end
    			end)
    		end
		end
	end)
end)

Any help would be appreciated.

1 Like

Why do you need ipairs? If you don’t want to detect them in order, this is not necessary.

I changed it to pairs but it still doesn’t work, it continues to increment by 2.

You set the .Touched connections every time the player loses a life. Instead, put those connections outside of the livesLeft.Changed connection.

The connections aren’t for when the player loses a life, it’s to close off the debounce timer (debounce remains on until the player gets teleported back). I tried putting it out regardless, and it made it so that you can’t lose any lives so it just stays at 3 forever.

I’ve done some changes and my new issue is at the part with .Changed:
local debounce = false

local triggers = { -- these are parts that should negate the debounce as these are your "start points"
	workspace.StartPart1,
	workspace.StartPart2,
	workspace.StartPart3,
	workspace.StartPart4,
	workspace.StartPart5,
	workspace.SpawnPart, -- in the lobby, in case your lives run out
}

local function onTouch(player)
	for _, part in pairs(triggers) do
		part.Touched:Connect(function(hit)
			if hit.Parent:FindFirstChildWhichIsA("Humanoid") then
				if game:GetService("Players"):GetPlayerFromCharacter(hit.Parent) == player then
					debounce = false -- if any of them are touched, and the player that touched them is the player of interest, then turn off the debounce so it resets it
				end
			end
		end)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	repeat wait(1) until player:FindFirstChild("LivesLeft")
	local livesLeft = player:FindFirstChild("LivesLeft") -- IntValue stores in player for lives left
	
	onTouch(player)
	
	livesLeft.Changed:Connect(function() -- ISSUE: it becomes a loop with livesLeft.Value += 1
		if debounce == true then
			livesLeft.Value += 1 -- should reverse impact of double-decreasing by increasing only one unit, but this does not work
			debounce = false
		else
			debounce = true -- if the debounce is not already on, turn it on
		end
	end)
end)

It constantly goes back and forth with the loop since adding the value of the livesLeft makes it go back up, which activates the .Changed loop, so far and so forth.

Update: I fixed the issue by deleting all individual kill scripts and combining it into one single script in ServerScriptService that cycles through all parts labeled “KillPart” and works on each one. This way, the debounce remained unified.