I would politely urge you to reread my top post. I explicitly stated I do not want to read terrain voxels, as they are extremely inaccurate and are in a 3d grid of 4 studs per block, and do not take into account waves
Set wave speed to 0 and make a timestamp to base your water clock cycle off of(best guess to roblox’s internal water clock cycle), plug that in to a wave function
+poopnugget142 Frankly, that’s not from a script. Roblox has this built-in as part of their graphics system
+tyridge I still don’t get how this will apply to cameras. So if you’d get the camera’s position and apply the wave function to it, won’t the modified position just wobble around aimlessly? I don’t get how that would help me detect if the camera is underwater or not.
…? Not sure what you’re saying.
If you want to get if the camera is under water, you need to see if it’s below the surface height. Wave function and clock hack detects surface height on a 2 dimensional plane
But what would be the surface height? I want it so that it would be able to detect water in any position, not just a single one. From what I believe you’re saying is that the wave function would work relative to the camera, meaning the modified position would just bob up and down based on the wave function.
local campos = workspace.CurrentCamera.CFrame.p
local surfacebaseray = Ray.new(campos,Vector3.new(0,-5,0))
local waterhit,waterpos,_ = workspace:FindPartOnRayWithWhitelist(surfacebaseray,{workspace.Terrain})
if waterhit then
local surfacebase = waterpos.Y + GetSurfaceHeightAtXZ(campos.x,campos.z)
if campos.y < surfacebase then
-- underwater
end
end
How do I implement this? I supposed I was supposed to put a print(“underwater”) in the - - underwater
but it doesn’t print it when the camera is underwater. I know this might seem impossible but it has been done multiple times, theme park tycoon 2, robloxian waterpark, ect.
Someone already linked you to the Surface Height function and you shot it down for being “needlessly complicated”
https://devforum.roblox.com/t/how-to-get-wave-height-at-a-specific-position/30672/3
Okay, now that I’ve implemented it it still doesn’t function.
local campos = workspace.CurrentCamera.CFrame.p local surfacebaseray = Ray.new(campos,Vector3.new(0,-5,0)) local waterhit,waterpos,_ = workspace:FindPartOnRayWithWhitelist(surfacebaseray,{workspace.Terrain}) function GetSurfaceHeightAtXZ(x,z) return 1.8 * math.sin(2*math.pi/85 * x) * math.sin(2*math.pi/85 * z) end if waterhit then local surfacebase = waterpos.Y + GetSurfaceHeightAtXZ(campos.x,campos.z) if campos.y < surfacebase then print('a') end end
I don’t know if what I did was wrong, please let me know
blobbybob’s solution on that post on the bottom is what you want. Keep in mind it seems to work best at a speed of 1 but with some trial and error and tinkering you should be able to get it working well with anything.
What is supposed to be the third argument “Cycle”?
Read the whole post, I’m on mobile now can’t really help much further
Okay, so I see it’s supposed to be the current water cycle, but how do get the cycle? It doesn’t mention anywhere in his post how
while wait() do if not _G.GetWaterWaveCycle then --We have to make sure the water's cycle is 0. There is no way to know this, --but if the WaterWaveSpeed is nonzero, there's a good chance the cycle is --nonzero. assert(workspace.Terrain.WaterWaveSpeed==0, "WaterWaveCycle cannot be defined after setting WaterWaveSpeed to" .."anything nonzero."); --This will not catch cases where the user changes the water wave speed from --a nonzero value to 0 then calls this code chunk, but I can't think of a way --to catch that case. --We just have to hope users use this correctly. local cycleAtLastSet = 0; --The cycle at the time of the last wave speed set. local tickAtLastSet = 0; --The tick() at the last WaterWaveSpeed set. local speedAtLastSet = 0; --The last WaterWaveSpeed which was set. --@return A float between 0 and 2pi indicating the current cycle. --@describe The cycle will be 0 when a place is freshly loaded and the -- WaterWaveSpeed is 0. function _G.GetWaterWaveCycle() return math.pi * 2 * ((cycleAtLastSet + (tick() - tickAtLastSet) * workspace.Terrain.WaterWaveSpeed / 85) % 1); end --Listen for changes to WaterWaveSpeed and update the state variables. workspace.Terrain.Changed:connect(function(prop) if prop == "WaterWaveSpeed" then cycleAtLastSet = (cycleAtLastSet + (tick() - tickAtLastSet) * speedAtLastSet / 85) % 1; print("Current Cycle State: ", cycleAtLastSet); tickAtLastSet = tick(); speedAtLastSet = workspace.Terrain.WaterWaveSpeed; end end) end local campos = workspace.CurrentCamera.CFrame.p local surfacebaseray = Ray.new(campos,Vector3.new(0,-5,0)) local waterhit,waterpos,_ = workspace:FindPartOnRayWithWhitelist(surfacebaseray,{workspace.Terrain}) local waveHeight = workspace.Terrain.WaterWaveSize * 2 local waveWidth = 85 function GetSurfaceHeightAtXZ(x, z, cycle) return waveHeight * math.sin(2*math.pi*x/waveWidth + cycle + math.pi/2) * math.sin(2*math.pi*z/waveWidth); end if waterhit then local surfacebase = waterpos.Y + GetSurfaceHeightAtXZ(campos.x,campos.z) if campos.y < surfacebase then print('a') end end end
Okay, so now I’m simply confused as to why the waterwavespeed should be 0. Shouldn’t it not be 0 for the waves to move?
Roblox’s internal clock increments when the speed isn’t 0, so if the speed is set to 0, then you change it to non zero, you can base the time elapsed since the change to get a guesstimate on the cycle. That’s what this does, is wait for you to set it to something other than 0, to set the tickAtLastSet variable to be used in GetWaterWaveCycle. But it needs to be 0 at the start
Alright, so it kind of works, but the waterwavespeed has to be set to 0, meaning the water is frozen, and also, it only works in a small area, I don’t know why.
Why is it like this?
I still haven’t figured it out
I haven’t figured it out quite yet