Hey, I am trying to make a custom water system that activates when you touch a part. Right now, there are 3 parts involved 1 for sound Fx (white), 1 for when you enter the water(Dark Blue) & one for when you leave (Light blue). It works by detecting a collision. when these 3 are separated it works fine but the problem is I need them to be close together. I have tried adding a debounce & I have even tried changing some collision groups around, but nothing seems to work. sometimes it picks up 2-3 collisions even though I added a debounce.
Here is a video demonstrating the problem:
I have seen some tutorials but they all show you how to make a different type of water system. in my water system you do not swim.
Enter Water script:
local IsTouched = false
local Brick = script.Parent
local PhysicsService = game:GetService("PhysicsService")
local Underwater = "Underwater"
function Water(hit)
if hit and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
local p = game.Players:GetPlayerFromCharacter(hit.Parent)
if not IsTouched then
IsTouched = true
wait()
print("entered water")
p.Character.PrimaryPart.CollisionGroup = Underwater
local breath = p.PlayerGui:WaitForChild("breathscript")
breath.Disabled = false
breath.Parent.Air.TextLabel.GUI.Disabled = false
breath.Parent.Air.TextLabel.Text = " "
p.PlayerGui.Air.TextLabel.Visible = true
p.PlayerGui.underwater.Frame.Visible = true
local hum = p.Character.HumanoidRootPart
local fx = hum.BubbleSplash
fx.Enabled = true
wait(0.1)
IsTouched = false
end
end
end
Brick.Touched:Connect(Water)
Leave water script:
local rep = game:GetService("ReplicatedStorage")
local FiredEvent = game.ReplicatedStorage.RemoteEvents:WaitForChild("AboveWater")
local IsTouched = false
local Brick = script.Parent
local PhysicsService = game:GetService("PhysicsService")
local AboveWater = "AboveWater"
function Water(hit)
if hit and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
local p = game.Players:GetPlayerFromCharacter(hit.Parent)
if not IsTouched then
IsTouched = true
wait()
print("left water")
p.Character.PrimaryPart.CollisionGroup = AboveWater
local air = p.PlayerGui:WaitForChild("addair")
local part = script.Parent
local breath = p.PlayerGui:WaitForChild("breathscript")
breath.Disabled = true
FiredEvent:FireClient(p)
p.PlayerGui.Air.TextLabel.Visible = false
p.PlayerGui.underwater.Frame.Visible = false
local hum = p.Character.HumanoidRootPart
local fx = hum.BubbleSplash
fx.Enabled = false
local FiredPart = rep.RemoteEvents:FindFirstChild("AirEvent")
FiredPart:FireClient(p, part)
wait(0.1)
IsTouched = false
end
end
end
Brick.Touched:Connect(Water)
local debounce = false
local function Water(hit)
if hit.Parent:FindFirstChild("Humanoid") then
if not debounce then
debounce = true
wait(0.5)
-- your code here
debounce = false
end
end
end
Brick.Touched:Connect(Water)
The code I provided should work fine. The only thing I can think of is that you might have more than one part touching the water part at the same time. You could try increasing the debounce time to see if that helps.
I just tried this but this only makes it even more buggy
Here is the code for that:
local Brick = script.Parent
local Underwater = "Underwater"
local rep = game:GetService("ReplicatedStorage")
local FiredEvent = game.ReplicatedStorage.RemoteEvents:WaitForChild("AboveWater")
local Brick = script.Parent
local AboveWater = "AboveWater"
script.Parent.Touched:Connect(function(hit)
if hit and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
local p = game.Players:GetPlayerFromCharacter(hit.Parent)
wait()
print("entered water")
p.Character.PrimaryPart.CollisionGroup = Underwater
local breath = p.PlayerGui:WaitForChild("breathscript")
breath.Disabled = false
breath.Parent.Air.TextLabel.GUI.Disabled = false
breath.Parent.Air.TextLabel.Text = " "
p.PlayerGui.Air.TextLabel.Visible = true
p.PlayerGui.underwater.Frame.Visible = true
local hum = p.Character.HumanoidRootPart
local fx = hum.BubbleSplash
fx.Enabled = true
end
end)
script.Parent.TouchEnded:Connect(function(hit)
if hit and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
local p = game.Players:GetPlayerFromCharacter(hit.Parent)
wait()
print("left water")
p.Character.PrimaryPart.CollisionGroup = AboveWater
local air = p.PlayerGui:WaitForChild("addair")
local part = script.Parent
local breath = p.PlayerGui:WaitForChild("breathscript")
breath.Disabled = true
FiredEvent:FireClient(p)
p.PlayerGui.Air.TextLabel.Visible = false
p.PlayerGui.underwater.Frame.Visible = false
local hum = p.Character.HumanoidRootPart
local fx = hum.BubbleSplash
fx.Enabled = false
local FiredPart = rep.RemoteEvents:FindFirstChild("AirEvent")
FiredPart:FireClient(p, part)
wait(0.1)
end
end)
This does not work. It basically is the same thing I wrote except with a local Infront of the function. and a few name changes I tried it though. here is the code:
Enter water script:
local PhysicsService = game:GetService("PhysicsService")
local Underwater = "Underwater"
local Debounce = false
local function Water(hit)
if hit.Parent:FindFirstChild("Humanoid") then
if not Debounce then
Debounce = true
wait(0.5)
local p = game.Players:GetPlayerFromCharacter(hit.Parent)
print("entered water")
p.Character.PrimaryPart.CollisionGroup = Underwater
local breath = p.PlayerGui:WaitForChild("breathscript")
breath.Disabled = false
breath.Parent.Air.TextLabel.GUI.Disabled = false
breath.Parent.Air.TextLabel.Text = " "
p.PlayerGui.Air.TextLabel.Visible = true
p.PlayerGui.underwater.Frame.Visible = true
local hum = p.Character.HumanoidRootPart
local fx = hum.BubbleSplash
fx.Enabled = true
wait(0.1)
Debounce = false
end
end
end
Brick.Touched:Connect(Water)
Leave water script:
local rep = game:GetService("ReplicatedStorage")
local FiredEvent = game.ReplicatedStorage.RemoteEvents:WaitForChild("AboveWater")
local Brick = script.Parent
local PhysicsService = game:GetService("PhysicsService")
local AboveWater = "AboveWater"
local Debounce = false
local function Water(hit)
if hit.Parent:FindFirstChild("Humanoid") then
if not Debounce then
Debounce = true
wait(0.5)
local p = game.Players:GetPlayerFromCharacter(hit.Parent)
print("left water")
p.Character.PrimaryPart.CollisionGroup = AboveWater
local air = p.PlayerGui:WaitForChild("addair")
local part = script.Parent
local breath = p.PlayerGui:WaitForChild("breathscript")
breath.Disabled = true
FiredEvent:FireClient(p)
p.PlayerGui.Air.TextLabel.Visible = false
p.PlayerGui.underwater.Frame.Visible = false
local hum = p.Character.HumanoidRootPart
local fx = hum.BubbleSplash
fx.Enabled = false
local FiredPart = rep.RemoteEvents:FindFirstChild("AirEvent")
FiredPart:FireClient(p, part)
wait(0.1)
Debounce = false
end
end
end
Brick.Touched:Connect(Water)
keep in mind these are 2 separate bricks but both of them are not working properly.
I tried making them into 1 brick with 1 script like @GamEditoPro said but it did not work.
You have TONS of useless stuff in your script.
Instead of creating tons of variables for every 1 need you can either group them in array, but in your situation, you don’t need any of that string variables like Underwater and AboveWater, and just set your collision group with string, not variable:
BasePart.CollisionGroup = "Underwater"
I’ll heavilly reccomend you use ModuleScripts instead of disabling any Scripts/LocalScripts in cases like your. Disabling scripts can break TONS of stuff, bc script after re-enabling will lose EVERYTHING it did. (I’m talking about things like counters)
Basically your waits are useless and can be main reason of bugs, bc yielding can break your logic combinations. So try delete them (Or comment).
Hey, Soo I cleaned up the script, I edited some stuff so that I don’t have to enable/disable anything at all. I took the waits out. But it still is very bugged. I have it as 2 parts one to enter and one to leave. It is the same bug as the other videos.
here is the enter water script:
local Brick = script.Parent
local PhysicsService = game:GetService("PhysicsService")
--local debounce = false
function Water(hit)
-- if debounce then return end
if hit and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
-- debounce = true
local p = game.Players:GetPlayerFromCharacter(hit.Parent)
if hit.Parent.PrimaryPart.CollisionGroup == "Default" or hit.Parent.PrimaryPart.CollisionGroup == "AboveWater" then
print "default"
p.Character.PrimaryPart.CollisionGroup = "Underwater"
local breath = p.PlayerGui:WaitForChild("breathscript")
breath.Breath.Value = 25
p.PlayerGui.Air.AirLeft.Visible = true
p.PlayerGui.underwater.Frame.Visible = true
end
-- wait(1)
-- debounce = false
end
end
Brick.Touched:Connect(Water)
.
.
.
.
.
here is the leave water script:
local Brick = script.Parent
local PhysicsService = game:GetService("PhysicsService")
---local debounce = false
function Water(hit)
-- if debounce then return end
if hit and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
---debounce = true
local p = game.Players:GetPlayerFromCharacter(hit.Parent)
if hit.Parent.PrimaryPart.CollisionGroup == "Underwater" then
print "UnderWater"
p.Character.PrimaryPart.CollisionGroup = "AboveWater"
local breath = p.PlayerGui:WaitForChild("breathscript")
breath.Breath.Value = 30
p.PlayerGui.Air.AirLeft.Visible = false
p.PlayerGui.underwater.Frame.Visible = false
end
-- wait(1)
-- debounce = false
end
end
Brick.Touched:Connect(Water)
Why you can’t combine this leave and enter water scripts into one?
Also, in your case I think you need check if HEAD is left or entered water. This may be one of reasons, bc for example 2 parts of same model eaxh can trigger function.
Hey, I really thought checking the head would work but it did not. it does work if I go through it slowly but this has been the case all along, but I need to be able to go through it at any speed as the speed increases when you dash and I might add speed boosters and stuff. I don’t want to make it all in one part because there are other touch events that need to happen like the big air bubble for example.
Also If I need to transfer the player to a level where they spawn underwater it is easier to make them fall on a part like in my game ex.
I currently have it working by duplicating the enter and exit parts several times but this is super buggy as you can see here:
Hey, I have been checking this out, it seems very complicated. also, I don’t want to have a giant part that acts as a region I want to have small parts that detect when you enter and exit.
ex:
Or you should use constant raycast from 6 sides of your character to detect is it in water part.
In your situation you will be unable to normally check if player is inside water or he left it. And you will be unable to make parts thin. Want know why?
Object’s positions can be changed only each heartbeat (frame). It’s defined by velocity of object. Due to this system, you can see smth very close to move, but actually they "teleport" a bit each time, so your character can just skip your thin part without actually touching it. There’s where your problem.
Hey man, you think you can give me a example? I made the part bigger and duplicated it alot so it detects it more. I also changed it back to detecting everything because the head is too small I think. It almost works. Sometimes it does sometimes it doesn’t it is working more tho.
Take a look at the place I have copying enabled:
There is also another script in starterGUI but I am sure this does not effect anything.
Now you have more funny situation, where you can touch BOTH parts at the same time, and due to this BOTH Leave and Start water even are trigger, and they will work by random order, and this’s another reason of bugs. So add spacing between that parts.
(To guaranteed detection your part thinkness and distance between them should be Walkspeed / HeartbeatPerSecond + CharacterMaxLength, so with 60 HPS and 200 Walkspeed you need make them 3.3333333333333333… + CharacterMaxLength studs)
But I think your game won’t have constant speed so you need use 1 GIANT part with touch ended event. This’s THE ONLY WAY TO SOLVE YOUR PROBLEM. If you want that thin parts, just make giant part invisible and thin ones visible.
Ok , im going to try to make 1 Big Giant part
I will let you know how it goes! I dont think it is convenient for me tho. Do I have to use overlap params I feel like Zone-plus has way too many scripts that I wont use. First Im going to try the distance.
your easiest solution is probably using zoneplus. you can allocate an entire folder of water parts to act as an ocean, where when inside ocean zone, then the player is in water, if not inzone, then the player is not in water.
sample code:
local Zone = require(ReplicatedStorage.Zone) --Zone module location
local OceanGroup1 = game.Workspace.map.Locations.Folder1 -- the group of parts as the ocean
local OceanZone1 = Zone.new(OceanGroup1) -- determine it as a Zone within zone module.
OceanZone1.playerEntered:Connect(function(player)
--whatever u want when player enters the area
end)
OceanZone1.playerExited:Connect(function(player)
--whatever u want when player leaves the area
end)
This works! only one problem. How would I go about putting a zone within a zone. Like a safe zone.
The way I have it set up is when you exit the water everything goes back to normal however I have an underwater bubble that is a safe zone, and everything is not intended to go back to normal when you are in the bubble.
this is the way I have it set up:
this almost always works but if you look around the 0.7 second mark you can see it does notI’d say every one out of 50 times it does not. although I think I know a work around for this (by adding more parts) but I’m sure there Is a more convenient way. is there?