You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

问题根源分析

  1. 部件嵌入物体:mouse.Hit返回的是射线击中物体的表面点,直接把部件中心放在这个点,必然会导致一半嵌入物体。需要根据射线的法线方向,将位置向外偏移半个部件的尺寸。
  2. 网格对齐逻辑冗余:原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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 19:36:00