Oxygen bar stopped working

I have an oxygen bar and it was working before, but now I realized that its not doing anything anymore when I go under my terrain water. Here is what I have:
Screen Shot 2021-10-10 at 11.37.10 AM

LocalScript inside GUI:

local player = game.Players.LocalPlayer
local Hum = player.Character:WaitForChild("Humanoid")
local background = script.Parent
local Bar = background:WaitForChild("Bar")
local OxygenText = background:WaitForChild("OxygenText")

OxygenText.Size = UDim2.new(1,0,1,0)

local oxyValue = player:WaitForChild("OxygenValue")

while wait(0.3) do
	Bar:TweenSize(UDim2.new(player.OxygenValue.Value/1000,0,1,0), "Out", "Quad", 0.3)
	OxygenText.Text = player.OxygenValue.Value.."/1000"
	if OxygenText.Text == "0/1000" then
		Hum.Health = 0
	end
end

Script in ServerScriptService:

game.Players.PlayerAdded:Connect(function(player)
	local increaseRate = 3
	local decreseRate = 2
	local oxygen = Instance.new("IntValue", player)
	oxygen.Value = 1000
	oxygen.Name = "OxygenValue"
	wait(3)
	while wait() do
		local char = player.Character or player.CharacterAdded:Wait()
		local castRay = Ray.new(char.Head.Position, Vector3.new(0,-10,0))
		local whiteList = {char}
		local hit, hitposition = workspace:FindPartOnRayWithIgnoreList(castRay, whiteList)
		local underwater = false
		if not hit or not hit:IsA("Terrain") then
			local castRay2 = Ray.new(char.Head.Position + Vector3.new(0,1000,0), Vector3.new(0,-1000,0))
			local hit2, hit2position = workspace:FindPartOnRayWithIgnoreList(castRay2, whiteList)
			if hit2 and hit2:IsA("Terrain") then
				underwater = true
			end
		end
		if underwater == false then
			oxygen.Value = math.clamp(oxygen.Value + increaseRate, 0, 1000)
		else
			oxygen.Value = math.clamp(oxygen.Value - decreseRate, 0, 1000)
		end
	end
end)

Are you getting any sort of errors? When I set up a sample place, it seemed to function as intended (oxygen went down in water and back up when out of water. I died at 0 oxygen).

One suggestion that may or may not help is to set up a more robust initializer on the server: if your game has Workspace.SignalBehavior set to Deferred, testing in Studio can sometime have your player join before running code that listens for that event (I believe this problem is exlusive to that setting, but it may happen in other cases). This results in none of your player initializer scripts running for that player, but it can be remedied with a small amount of code, like this:

--Declare the initializer as a first-class function.
local function player_added(player)
	local increaseRate = 3
	local decreseRate = 2
	local oxygen = Instance.new("IntValue", player)
	oxygen.Value = 1000
	oxygen.Name = "OxygenValue"
	wait(3)
	while wait() do
		local char = player.Character or player.CharacterAdded:Wait()
		local castRay = Ray.new(char.Head.Position, Vector3.new(0,-10,0))
		local whiteList = {char}
		local hit, hitposition = workspace:FindPartOnRayWithIgnoreList(castRay, whiteList)
		local underwater = false
		if not hit or not hit:IsA("Terrain") then
			local castRay2 = Ray.new(char.Head.Position + Vector3.new(0,1000,0), Vector3.new(0,-1000,0))
			local hit2, hit2position = workspace:FindPartOnRayWithIgnoreList(castRay2, whiteList)
			if hit2 and hit2:IsA("Terrain") then
				underwater = true
			end
		end
		if underwater == false then
			oxygen.Value = math.clamp(oxygen.Value + increaseRate, 0, 1000)
		else
			oxygen.Value = math.clamp(oxygen.Value - decreseRate, 0, 1000)
		end
	end
end

local players = game:GetService("Players")
--Hook into the event like normal.
players.PlayerAdded:Connect(player_added)
--Initialize any players that may have been able to join before the event connection was made.
for _,player in ipairs(players:GetPlayers()) do
	player_added(player)
end

I don’t have any errors and mine used to do the exact same thing yours did and I checked the setup of my water and everything but I never changed anything

I think I figured out a potential issue: the code can’t differentiate between the surface of water and the bottom of a terrain lake. If you are in water–even if completely submerged–but close to terrain ground at the bottom, the code will think you’re above water.

It doesn’t seem like the old raycast methods are able to make this distinction. This code uses the newer methods and should be able to differentiate between terrain ground and the surface of the water:

local water_material = Enum.Material.Water

local V3_n10 = Vector3.new(0,-10,0)
local V3_1000 = Vector3.new(0,1000,0)
local V3_n1000 = Vector3.new(0,-1000,0)

--Declare the initializer as a first-class function.
local function player_added(player)
	local increaseRate = 3
	local decreseRate = 2
	local oxygen = Instance.new("IntValue", player)
	oxygen.Value = 1000
	oxygen.Name = "OxygenValue"
	wait(3)
	
	local raycast_params = RaycastParams.new()
	raycast_params.FilterType = Enum.RaycastFilterType.Blacklist
	
	while wait() do
		local char = player.Character or player.CharacterAdded:Wait()
		raycast_params.FilterDescendantsInstances = {char}
		local collision = workspace:Raycast(char.Head.Position,V3_n10,raycast_params)
		local underwater = false
		if not (collision and collision.Material == water_material) then
			collision = workspace:Raycast(char.Head.Position + V3_1000,V3_n1000,raycast_params)
			if collision and collision.Material == water_material then
				underwater = true
			end
		end
		if underwater == false then
			oxygen.Value = math.clamp(oxygen.Value + increaseRate, 0, 1000)
		else
			oxygen.Value = math.clamp(oxygen.Value - decreseRate, 0, 1000)
		end
	end
end

local players = game:GetService("Players")
--Hook into the event like normal.
players.PlayerAdded:Connect(player_added)
--Initialize any players that may have been able to join before the event connection was made.
for _,player in ipairs(players:GetPlayers()) do
	player_added(player)
end

1 Like

im not good at these kind of things but

i feel like there’s something wrong with this

cause one thing that may happen is if you’re below water but there is water above you in a 1k stud distance, you may still drown

1 Like

Oh yea that happened I have a secret room and you lose oxygen when you’re in it even tho there’s water above you and you’re not in water but I fixed that by disabling it until you get out and then once you get out the oxygen will just refill

I tried both scripts you provided and they didn’t work it still does nothing

Another issue seems to be if a block is above the player, as it would block the “underwater check” raycast. This code will resolve that issue:

local water_material = Enum.Material.Water

local V3_n10 = Vector3.new(0,-10,0)
local V3_1000 = Vector3.new(0,1000,0)
local V3_n1000 = Vector3.new(0,-1000,0)

local raycast_params = RaycastParams.new()
raycast_params.FilterType = Enum.RaycastFilterType.Whitelist
raycast_params.FilterDescendantsInstances = {workspace.Terrain}

local function player_added(player)
	local increaseRate = 3
	local decreseRate = 2
	local oxygen = Instance.new("IntValue", player)
	oxygen.Value = 1000
	oxygen.Name = "OxygenValue"
	wait(3)
	
	while wait() do
		local char = player.Character or player.CharacterAdded:Wait()
		local collision = workspace:Raycast(char.Head.Position,V3_n10,raycast_params)
		local underwater = false
		if not (collision and collision.Material == water_material) then
			collision = workspace:Raycast(char.Head.Position + V3_1000,V3_n1000,raycast_params)
			if collision and collision.Material == water_material then
				underwater = true
			end
		end
		if underwater == false then
			oxygen.Value = math.clamp(oxygen.Value + increaseRate, 0, 1000)
		else
			oxygen.Value = math.clamp(oxygen.Value - decreseRate, 0, 1000)
		end
	end
end

local players = game:GetService("Players")
players.PlayerAdded:Connect(player_added)
for _,player in ipairs(players:GetPlayers()) do
	player_added(player)
end

The raycasts in this code only hit Terrain now, but what this means is that any Terrain above the player who is in water will result in the code thinking they are on land. Fixing that issue would require a fundamentally different approach to the problem, since raycasts can be configured to ignore water but not normal terrain. If you have any terrain caves, this oxygen system will not work in them.

If you are continuing to have issues beyond this point, I’ll need more insight into your setup as to why things aren’t working–be it variable values at breakpoints or map structure or something–as I’m able to get results on my end minus the conditions each post sets out to remedy.

1 Like