I think that (Vector3.new(0.5, 0.5, 0.5), Vector3.new(0.5, 0.5, 0.5))
would also work. Region3s aren’t precise (they snap to a voxel grid) .
Min probably gets round down to the nearest grid point while max gets round up to the nearest grid point. If both points happen to fall exactly on the grid, then neither point gets rounded.
But yeah, to avoid pesky edge cases, min and max shouldn’t be the same.
EDIT: Behold, (Vector3.new(0.5, 0.5, 0.5), Vector3.new(0.5, 0.5, 0.5))
does work:
NOTE: This also means that you can’t rely on just FindPartsInRegion3 to check if a point on the map is occupied! You can use this in your broadphase (if FindPartsInRegion3 returns nothing you can be sure that there’s nothing on that point, otherwise you’ll need to do more stuff to be sure.) If everything in your map is convex, then you can raycast from the point you want to check to the center of the part with only the part in its whitelist. If there’s a hit, it must be outside part, otherwise it’s inside the part.
EDIT2:
Here’s a function that checks if a point in the world is occupied by something. Like I said, non-convex meshes will throw this off. I hope your map doesn’t have donuts.
local function isPointInMapOccupied(p)
-- Fudge the region by a bit to avoid the edgecase you saw in OP.
local region = Region3.new(p, p+Vector3.new(1, 1, 1))
local possible = workspace:FindPartsInRegion3(region, 10000)
-- Broadphase: The region is bigger than the point and the region is empty.
-- Therefore, there must be nothing in this point.
if #possible == 0 then return false end
-- Test each part in the region via raycast.
for _, part in next, possible do
-- Raycast to the center of the part.
local ray = Ray.new(p, part.Position-p)
-- If we don't hit the part, then the point must be inside of the part.
if next(workspace:FindPartOnRayWithWhitelist(ray, {part})) == nil then
return true
end
end
return false
end