I need to make an oxygen bar in my game that decreases when you go in water and increases when you come out of water. The only thing is that I want to do this by reading terrain voxels since you can gain oxygen just by getting your head out of the water which i would need to do for my game. (a beach game) The only problem is that i don’t know how to make and script this. Does anyone know how to do this?
Hm, maybe use raycasting? I think that’s your best option.
touching terrain parts check??
This worked perfectly for me! The “oxygen” value will increase when they are above water and decrease when they are below water.
game.Players.PlayerAdded:Connect(function(player)
local oxygen = Instance.new("IntValue", player)
oxygen.Value = 1000
oxygen.Name = "OxygenValue"
local increaseRate = 3 --how fast it increases
local decreseRate = 2 --how fast it decreases
local maxOxygen = 1000 --change accordingly
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 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 then
underwater = true
end
end
if underwater == false then
oxygen.Value = math.clamp(oxygen.Value + increaseRate, 0, maxOxygen)
else
oxygen.Value = math.clamp(oxygen.Value - decreseRate, 0, maxOxygen)
end
print(oxygen)
end
end)
In the following video, look at the output on the left. You can see the oxygen increase when I come out of the water and decrease when I become submerged:
https://gyazo.com/a526b1333c207e12194a9d07149e5779
Would I use this with like a GUI or does it work without one
Yes, you can change the size of a gui or something.
Ok so if I use it with a GUI then where would I put this script
Oh neat, check my free model. It’s pretty old and I’m uncertain of it’s functionality but I do know it was in a state of working a few years ago at minimum.
You can grab whatever assets I have with the model, but here is some source code I just now pulled from it This should operate an Oxygen Bar when your head (or however accurate you can check w/ voxels) exits Terrain Water.
local SurfaceGui = script.Parent
local OA = SurfaceGui.Frame.OxygenBar
local Plr = game.Players.LocalPlayer
repeat wait() until Plr.Character
local Hum = Plr.Character:WaitForChild("Humanoid")
local cOxygen, MaxOxygen= 20, 20 -- 1 = 1 second of air
local Swim = false
local UIS = game:GetService("UserInputService")
local T = game.Workspace:WaitForChild("Terrain")
local Ended = true
function UnderWaterCheck(Head)
if Head then
local InWater = true
local Offset = Head.Size / 2
local P1, P2 = (Head.Position - Vector3.new(1, 0, 0)) - Offset, (Head.Position + Vector3.new(1, 0, 0)) + Offset
local R3 = Region3.new(P1, P2):ExpandToGrid(4)
local Tbl = T:ReadVoxels(R3, 4)
for _, Material in pairs(Tbl[2][1]) do
if Material == Enum.Material.Air then
InWater = false
end
end
return InWater
end
end
Hum.Swimming:connect(function()
if not Swim then
SurfaceGui.Frame.Visible = true
Swim = true
end
UIS.InputBegan:connect(function(Pressed)
if Swim and Pressed.KeyCode == Enum.KeyCode.Space then
Ended = false
UIS.InputEnded:connect(function(Released)
if Swim and Released.KeyCode == Enum.KeyCode.Space then
Ended = true
end
end)
repeat wait()
if not UnderWaterCheck(Hum.Parent.Head) and Swim then
Swim = false
SurfaceGui.Frame.Visible = false
cOxygen = MaxOxygen
OA:TweenSize(UDim2.new(cOxygen/MaxOxygen,0, 1,0), "Out", "Linear", .3, true)
Ended = true
end
until Hum.Health == 0 or Ended or not Swim
end
end)
Hum.Running:connect(function()
if Swim then
SurfaceGui.Frame.Visible = false
Swim = false
cOxygen = MaxOxygen
end
end)
end)
while wait(1) do
OA:TweenSize(UDim2.new(cOxygen/MaxOxygen,0, 1,0), "Out", "Linear", 1, true)
if Swim then
if cOxygen - 1 > 0 then
cOxygen = cOxygen - 1
else
Hum.Health = 0 --Kill the player, no oxygen left
end
else
if cOxygen ~= MaxOxygen and Hum.Health > 0 then
cOxygen = MaxOxygen
end
end
end
Put the other script in ServerScriptService, then put the following script as the child of a textlabel.
Here is a picture of the explorer:
The "Bar textlabel’ should be green and the “Background textlabel” should be grey. The “OxygenText Textlabel” should have a background transparency of 1.
LOCAL SCRIPT (This must be a direct child of the “Background” textlabel.)
local player = game.Players.LocalPlayer
local background = script.Parent
local Bar = background:WaitForChild("Bar")
local OxygenText = background:WaitForChild("OxygenText")
OxygenText.Size = UDim2.new(1,0,1,0)
while wait(0.3) do
Bar:TweenSize(UDim2.new(player.OxygenValue.Value/1000,0,1,0))
OxygenText.Text = player.OxygenValue.Value.."/1000"
end
This doesn’t work for me because even when your head comes out of the water you still lose oxygen
You’ll likely have to jump out higher then, Voxels don’t offer a high resolution for checks like you want. However I do believe this is the method for “an oxygen bar by reading terrain voxels”,
Oh because I saw in a post someone was able to do what I wanted to do ill link the post I just dont know how to do it the way they did it
https://devforum.roblox.com/t/how-can-i-get-an-oxygen-bar/1083223
Theres also a video in that post showing it working
I’ve seen this question many times in DevForum. You tried to search for an answer?
The best way I found to do it, is by Reading Voxels on top of the Character’s Head.
You need to use
Terrain:WorldToCell
,Region3
andTerrain:ReadVoxels
Once you read the Voxels material over the head of the character, if its water, drain oxygen, if its air increase oxygen.
Took me many tests to achieve it, I tried raycasting and many weird creative ways to do it… But I found Reading Voxels works perfect.
Instead of reading terrain voxels, I’d suggest reading the humanoids state, and detect if the player is swimming or not, that way you don’t have to deal with the inconsistency of terrain checks.
If I did that I don’t think it would work because if you’re above water wouldn’t you still be using the swimming animation
Sorry for not responding, i was away. I know this works because it worked for me. The script that I first gave you is supposed to be a server script in server script service. This is the script that should be the local script:
local player = game.Players.LocalPlayer
local background = script.Parent
local Bar = background:WaitForChild("Bar")
local OxygenText = background:WaitForChild("OxygenText")
OxygenText.Size = UDim2.new(1,0,1,0)
while wait(0.3) do
Bar:TweenSize(UDim2.new(player.OxygenValue.Value/1000,0,1,0))
OxygenText.Text = player.OxygenValue.Value.."/1000"
end
yea ik thats how I have it and it isnt working
Any errors in the output or anything?
Ill check the output I also designed the GUI a different way but the names are the same so I dont see how that would be an issue
On my end I only tested the oxygen part, not the GUI code. I’ll test it and fix anything that is wrong then I’ll get back to you.