Roblox建造工具问题:mouse.hit放置部件嵌入物体的解决问询
Roblox建造工具放置位置错误问题修复
我在Roblox做一款用工具建造的游戏,用mouse.hit获取部件放置位置时,部件总放错地方。试过各种方案,当前代码效果相对最好,但仍有两个问题:
- 部件会一半嵌入点击的物体
- 3 studs网格对齐脚本导致部件嵌入其他物体,或网格对齐失效
原问题代码
local tool = script.Parent local blocks = game.ReplicatedStorage.Blocks local previews = game.ReplicatedStorage.Previews local mouse = game.Players.LocalPlayer:GetMouse() local preview = nil local x, y, z = nil local eventFinish = false local event = tool.Unequipped:connect(function() eventFinish = true end) -- 网格对齐函数 function snap(x, y, z) x = math.round(x) y = math.round(y) z = math.round(z) if (x + 1) / 3 == math.round((x + 1) / 3) then x = x + 1 elseif (x - 1) / 3 == math.round((x - 1) / 3) then x = x - 1 end if (y + 1) / 3 == math.round((y + 1) / 3) then y = y + 1 elseif (y - 1) / 3 == math.round((y - 1) / 3) then y = y - 1 end if (z + 1) / 3 == math.round((z + 1) / 3) then z = z + 1 elseif (z - 1) / 3 == math.round((z - 1) / 3) then z = z - 1 end x += 0.5 y += 1.5 z += 0.5 return Vector3.new(x, y, z) end tool.Activated:Connect(function() eventFinish = true wait(0) eventFinish = false tool.Place:FireServer(blocks.Block, snap(mouse.Hit.X, mouse.Hit.Y, mouse.Hit.Z)) repeat if preview ~= nil then preview:Destroy() end preview = previews.Block:Clone() preview.Position = snap(mouse.Hit.X, mouse.Hit.Y, mouse.Hit.Z) preview.Parent = game.Workspace wait(0) until eventFinish == true preview:Destroy() preview = nil eventFinish = false end) tool.Equipped:Connect(function() repeat if preview ~= nil then preview:Destroy() end preview = previews.Block:Clone() preview.Position = snap(mouse.Hit.X, mouse.Hit.Y, mouse.Hit.Z) preview.Parent = game.Workspace wait(0) until eventFinish == true preview:Destroy() preview = nil eventFinish = false end)
问题根源分析
- 部件嵌入物体:
mouse.Hit返回的是射线击中物体的表面点,直接把部件中心放在这个点,必然会导致一半嵌入物体。需要根据射线的法线方向,将位置向外偏移半个部件的尺寸。 - 网格对齐逻辑冗余:原
snap函数的判断逻辑绕,容易出现计算错误,应该直接基于3 studs的网格步长来计算对齐位置。
修复后的代码
local tool = script.Parent local blocks = game.ReplicatedStorage.Blocks local previews = game.ReplicatedStorage.Previews local mouse = game.Players.LocalPlayer:GetMouse() local preview = nil local eventFinish = false local BLOCK_SIZE = Vector3.new(3, 3, 3) -- 假设部件是3x3x3 studs,根据实际调整 local GRID_STEP = 3 -- 网格步长 tool.Unequipped:Connect(function() eventFinish = true end) -- 简化的网格对齐函数:将位置对齐到3 studs网格,确保部件中心落在网格点上 function snapToGrid(position) local snappedX = math.round(position.X / GRID_STEP) * GRID_STEP local snappedY = math.round(position.Y / GRID_STEP) * GRID_STEP local snappedZ = math.round(position.Z / GRID_STEP) * GRID_STEP return Vector3.new(snappedX, snappedY, snappedZ) end -- 获取正确的放置位置:避免嵌入物体,同时对齐网格 function getPlacementPosition() local hit = mouse.Hit if not hit then return Vector3.new(0, 0, 0) end -- 向外偏移半个部件尺寸,防止嵌入 local offset = hit.Normal * (BLOCK_SIZE / 2) local rawPosition = hit.Position + offset -- 对齐到网格 return snapToGrid(rawPosition) end -- 更新预览部件的函数,避免重复代码 function updatePreview() if preview then preview:Destroy() end preview = previews.Block:Clone() preview.Position = getPlacementPosition() preview.Parent = workspace end tool.Equipped:Connect(function() eventFinish = false repeat updatePreview() task.wait() -- 用task.wait()替代wait(0),更高效 until eventFinish == true if preview then preview:Destroy() preview = nil end end) tool.Activated:Connect(function() eventFinish = true task.wait() eventFinish = false -- 发送正确的放置位置到服务器 tool.Place:FireServer(blocks.Block, getPlacementPosition()) -- 重启预览循环 repeat updatePreview() task.wait() until eventFinish == true if preview then preview:Destroy() preview = nil end end)
关键修复点说明
- 防止部件嵌入:通过
hit.Normal * (BLOCK_SIZE / 2)计算偏移量,将位置从物体表面向外推半个部件的尺寸,确保部件完全放在物体外部。 - 简化网格对齐:直接用
math.round(position / GRID_STEP) * GRID_STEP实现对齐,逻辑清晰不易出错,确保部件中心严格对齐3 studs网格。 - 代码复用:把预览更新逻辑抽成
updatePreview函数,减少重复代码,维护更方便。 - 高效等待:用
task.wait()替代wait(0),Roblox推荐使用前者,性能更稳定。
额外建议
- 如果你的部件尺寸不是3x3x3,记得修改
BLOCK_SIZE为实际尺寸。 - 可以给射线添加过滤,比如忽略预览部件和玩家角色,避免误击中不需要的物体:
mouse.TargetFilter = preview(在updatePreview里设置)。
内容的提问来源于stack exchange,提问作者random guy189283
相关产品推荐
相关产品推荐

