I’m making a lidar system right now but I’m running into the issue where dots will be placed on top of dots, despite their CanQuery being false, and them supposedly meant to be checking if anything occupies the grid
I assume the best way would be by checking the distances maybe but I don’t want to cause any unnecessary lag that is already currently being caused
-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
-- Objects
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Camera = workspace.CurrentCamera
local MapBlocks = workspace:WaitForChild("MapBlocks")
local WorldDots = workspace:WaitForChild("Dots")
local DotReserve = WorldDots:WaitForChild("DotReserve")
-- Storage
local ScanAction = ReplicatedStorage.InputContexts.Gameplay.Scan
local TemplateDot = script:WaitForChild("Dot")
-- Modules
local SharedModules = ReplicatedStorage.Modules.Shared
local PartCache = require(SharedModules:WaitForChild("PartCache"))
-- Caches
local DotCache = PartCache.new(TemplateDot, 1500, DotReserve)
local DotGrid = {}
-- Values
local LastScan = os.clock()
local Step = 10 / (25 - 1)
local Offset = -10 / 2
local MaxRaycast = 50
local ScanParams = RaycastParams.new()
ScanParams.FilterType = Enum.RaycastFilterType.Exclude
ScanAction.Pressed:Connect(function()
if (os.clock() - LastScan) > 1 then
LastScan = os.clock()
local CameraPivot = Camera:GetPivot()
local Direction = CameraPivot.LookVector * 45
local RaycastCount = 0
local ScanTable = {Character}
for _, v in CollectionService:GetTagged("ScanDot") do table.insert(ScanTable, v) end
ScanParams.FilterDescendantsInstances = ScanTable
for X = 0, 25 - 1 do
for Y = 0, 25 - 1 do
local XOffset = Offset + (X * Step)
local YOffset = Offset + (Y * Step)
local Origin = CameraPivot.Position + CameraPivot.RightVector * XOffset + CameraPivot.UpVector * YOffset
local Cast = workspace:Raycast(Origin, Direction, ScanParams)
if Cast then
local CastPosition = Cast.Position
local GridPosition = Vector3.new(math.floor(CastPosition.X), math.floor(CastPosition.Y), math.floor(CastPosition.Z))
if not DotGrid[GridPosition] then
local NewDot = DotCache:GetPart()
NewDot.Position = GridPosition
DotGrid[GridPosition] = NewDot
end
end
RaycastCount += 1
if RaycastCount >= MaxRaycast then
RaycastCount = 0
RunService.Heartbeat:Wait()
end
end
end
end
end)
if you aren’t going to be helpful please don’t respond. canquery is a boolean on parts you can disable which makes them get ignored by raycasts that don’t have respectcancollide
my setup does happen to have L shaped walls so I believe that could possibly be why? I don’t think the part cache would do anything but I’m interested in what you did anyway
here's the script i used (it's updated version of yours)
--!strict
const DeleteDelay = 1
-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
-- Objects
local Player = assert(Players.LocalPlayer)
local Character = Player.Character or Player.CharacterAdded:Wait()
local Camera = assert(workspace.CurrentCamera)
-- Storage
local ScanAction = ReplicatedStorage.InputContexts.Gameplay.Scan
-- Caches
local DotGrid = {}
-- Values
local LastScan = os.clock()
local Step = 10 / (25 - 1)
local Offset = -10 / 2
local MaxRaycast = 50
local ScanParams = RaycastParams.new()
ScanParams.FilterType = Enum.RaycastFilterType.Exclude
local index = 0
local function createDot(position: Vector3, color: Color3)
local NewDot = Instance.new("Part")
NewDot.Name = "dot_" .. tostring(index)
NewDot.Transparency = .25
NewDot.Size = Vector3.one * .5
NewDot.Anchored = true
NewDot.CanQuery = false
NewDot.CanCollide = false
NewDot.Position = position
NewDot.Material = Enum.Material.Neon
NewDot.Color = color
NewDot.Parent = workspace.Dots
index += 1
return NewDot
end
ScanAction.Pressed:Connect(function()
print("ScanAction.Pressed")
if (os.clock() - LastScan) > 1 then
LastScan = os.clock()
local CameraPivot = Camera:GetPivot()
local Direction = CameraPivot.LookVector * 45
local RaycastCount = 0
ScanParams.FilterDescendantsInstances = {Character}
for X = 0, 25 - 1 do
for Y = 0, 25 - 1 do
local XOffset = Offset + (X * Step)
local YOffset = Offset + (Y * Step)
local Origin = CameraPivot.Position + CameraPivot.RightVector * XOffset + CameraPivot.UpVector * YOffset
local Cast = workspace:Raycast(Origin, Direction, ScanParams)
if Cast then
local CastPosition = Cast.Position
local GridPosition = Vector3.new(math.floor(CastPosition.X), math.floor(CastPosition.Y), math.floor(CastPosition.Z))
if not DotGrid[GridPosition] then
local NewDot = createDot(GridPosition, Color3.new(0, 1, 0))
Debris:AddItem(NewDot, DeleteDelay)
NewDot.AncestryChanged:Once(function(child: Instance, parent: Instance)
assert(not parent)
createDot(NewDot.Position, Color3.new(1, 1, 0))
end)
DotGrid[GridPosition] = NewDot
end
end
RaycastCount += 1
if RaycastCount >= MaxRaycast then
RaycastCount = 0
RunService.Heartbeat:Wait()
end
end
end
end
end)
workspace.Dots.ChildAdded:Connect(function(child: Instance)
print("child", child)
end)
Here’s the video:
dots do not overlap: pressing Scan without moving camera does not add dots to occupied positions
the problem is definitely not in math.floor(CastPosition.X), math.floor(CastPosition.Y), math.floor(CastPosition.Z)
you can test that Vector3 == operator works correctly easily with:
local t = {}
t[Vector3.new()] = true
t[Vector3.new()] = true
print(t)
two different Vector3 instances have been put into the table
table size == 1 because their value is the same
The problem is somewhere else. Please check your code.
What’s likely happening in your case is that dot at
DotGrid[GridPosition]
actually does not have its .Position == GridPosition
If your walls are Meshes and L shaped it could be that the Box Collision Fidility is to course and raycast hits it + math.floor so they float, try PerciseConvexDecomposition (if that is the case). And my partcache just creates parts that have no CanQuery and CanCollide set to false and it creates them 10000 times or so and if it exceeds the cached, it creates new ones and places them at the position.
could you please post the screenshot again with circles around overlapped dots?
could you please provide experience file with just models that you scan to achieve overlapped dots, so we can check the meshes also?
thank you!
could you please clarify that?
what does “on top of each other” mean for you? they occupy same place in 3d space? or they appear at the same place on screen?
they are physically on top of each other and offset via the grid, please look at the screenshot and test the game, I do not think I can explain it any better