How does the BuoyancySensor work?

How does the BuoyancySensor exactly work? Whenever the object is touching the water it fires TouchingSurface = false, however whenever the object is touching the surface it also fires TouchingSurface = false, and sometimes it even gets reversed and on both of these fires = true, I simply do not understand how this thing exactly works. The roblox Documentation isn’t much help.

Here are some screenshots to show you what i mean


The code I use is fairly simple

        print(bobber.BuoyancySensor.TouchingSurface)
        local touchsurface = bobber.BuoyancySensor.TouchingSurface
		if touchsurface == false then
			print("player is fish")
		elseif touchsurface == true then
			print("player is not fish")
		end

All that I want to achieve is for it to read properly whenever the object is touching water and whenever not. And yes the UpdateType is set to OnRead

1 Like

Use the Terrain APIs to check for nearby water voxels

I just tried something like that, however it doesn’t seem to detect any terrain at all.

The code i used:

local REGION_START = object.Position
   	local REGION_END = object.Position

   	local function printRegion(terrain, region)
   		local materials, occupancies = terrain:ReadVoxels(region, 1)

   		local size = materials.Size -- Same as occupancies.Size

   		for x = 1, size.X, 1 do
   			for y = 1, size.Y, 1 do
   				for z = 1, size.Z, 1 do
   					print(("(%2i, %2i, %2i): %.2f %s"):format(x, y, z, occupancies[x][y][z], materials[x][y][z].Name))
   				end
   			end
   		end
   	end

   	local region = Region3.new(REGION_START, REGION_END)

   	print(printRegion(workspace.Terrain, region))

You can refer to these two resources for a better explanation.


Notes to your Issue

TouchingSurface

This property is true when any position on the BasePart is touching Terrain water. The detection measurements are not exact and may use the bounding box of the part instead of its exact geometry.

FullySubmerged

This property is true when the entirety of the BasePart is submerged in Terrain water with at least one voxel of water above it.


Bounding Box Code Sample

Summary

This function returns a description of a volume that contains all BasePart children within a Model. The volume’s orientation is based on the orientation of the PrimaryPart, and matches the selection box rendered in Studio when the model is selected. Mirroring the behavior of Terrain:FillBlock(), it returns a CFrame representing the center of that bounding box and a Vector3 representing its size.

If there is no PrimaryPart for the model, the bounding box will be aligned to the world axes.

Returns

A CFrame representing the orientation of the volume followed by a Vector3 representing the size of the volume.

local Workspace = game:GetService("Workspace")

local model = Workspace.Model
local part = Workspace.Part
local orientation, size = model:GetBoundingBox()

-- Resize and position part equal to bounding box of model
part.Size = size
part.CFrame = orientation
1 Like

Yes, I managed to find a way to make it work. What i did was Instance a new part parented to workspace and then the sensor with the sensor being parented to the part and then checking if the part is touching the water. This ended up working. Thank you!

1 Like

I also made some detection with another method.

local Bob = script.Parent

function GetBobBoundingBox() : (CFrame, Vector3)
	local transform = Bob.CFrame
	local size = Bob.Size
	if Bob:IsA("Model") then
		transform, size = Bob:GetBoundingBox()
	end
	return transform, size
end

while task.wait(1) do
	local transform, size = GetBobBoundingBox()
	
	-- check if touching water
	local min = transform.Position - (0.5 * size)
	local max = transform.Position + (0.5 * size)
	local bobRegion = Region3.new(min,max):ExpandToGrid(4)
	local material = workspace.Terrain:ReadVoxels(bobRegion, 4)[1][1][1]
	
	if material == Enum.Material.Water then
		print("In water!")
	else
		print("Not in water.")
	end
end