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

Unity C#基于网格的建筑系统无法正常工作 技术求助

修复类似Rust风格的网格建筑吸附系统

嘿,我看你在做生存游戏的网格建筑系统,目前的代码不仅有逻辑缺失,还有一些小问题,而且Raycast部分还截断了——先帮你梳理下现有代码的问题,再给你一套能正常运行的完整实现方案!

现有代码的明显问题

  • 重复计算浪费性能:你在Start()和Update()里都计算了gridSize = 1f / gridDistance,Update里每帧都算完全没必要,而且这个计算逻辑其实可以简化。
  • 核心网格转换逻辑缺失:代码里定义了gridPosition但没做任何转换计算,这是实现网格吸附的核心步骤。
  • Raycast代码不完整:Camera.ma...应该是要获取鼠标射线来检测场景中的放置平面,这部分是实现“跟着鼠标预览建筑位置”的关键,你没写完。
  • 没有预览/放置逻辑:Rust风格的建筑系统需要实时显示预览模型,以及触发放置的输入处理,这些你的代码里都没有。

修复后的完整代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SnapToGrid : MonoBehaviour
{
    [Header("建筑设置")]
    public GameObject buildingPrefab;
    public float gridDistance = 2f; // 每个网格单元的大小(比如2米)
    public LayerMask placementLayer; // 允许放置建筑的层(比如地面层)

    private GameObject previewObject;
    private float gridHalfSize; // 辅助计算网格中心对齐

    void Start()
    {
        // 提前计算网格半尺寸,用来让建筑中心对齐网格
        gridHalfSize = gridDistance / 2f;
        // 初始化预览对象
        CreatePreviewObject();
    }

    void Update()
    {
        // 获取鼠标射线,检测场景中的放置平面
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, placementLayer))
        {
            // 将检测到的世界坐标转换为网格对齐坐标
            Vector3 gridAlignedPos = GetGridAlignedPosition(hit.point);
            // 更新预览对象的位置
            UpdatePreviewPosition(gridAlignedPos);

            // 鼠标左键点击时放置建筑
            if (Input.GetMouseButtonDown(0))
            {
                PlaceBuilding(gridAlignedPos);
            }
        }
        else
        {
            // 没检测到放置平面时隐藏预览
            if (previewObject != null)
                previewObject.SetActive(false);
        }
    }

    // 将世界坐标转换为网格对齐坐标
    private Vector3 GetGridAlignedPosition(Vector3 worldPos)
    {
        // 按网格大小取整,然后加上半尺寸让建筑中心对齐网格
        float x = Mathf.Round(worldPos.x / gridDistance) * gridDistance + gridHalfSize;
        float y = Mathf.Round(worldPos.y / gridDistance) * gridDistance + gridHalfSize;
        float z = Mathf.Round(worldPos.z / gridDistance) * gridDistance + gridHalfSize;

        return new Vector3(x, y, z);
    }

    // 创建预览对象(复制预制体,禁用碰撞和渲染以外的组件)
    private void CreatePreviewObject()
    {
        if (buildingPrefab == null) return;

        previewObject = Instantiate(buildingPrefab);
        // 禁用预览对象的碰撞和脚本,避免影响游戏逻辑
        Collider[] colliders = previewObject.GetComponents<Collider>();
        foreach (Collider col in colliders)
            col.enabled = false;

        // 给预览对象添加半透明材质,区分正式建筑
        Renderer[] renderers = previewObject.GetComponentsInChildren<Renderer>();
        foreach (Renderer rend in renderers)
        {
            Material previewMat = new Material(rend.material);
            previewMat.color = new Color(rend.material.color.r, rend.material.color.g, rend.material.color.b, 0.5f);
            rend.material = previewMat;
        }
    }

    // 更新预览对象的位置
    private void UpdatePreviewPosition(Vector3 targetPos)
    {
        if (previewObject == null) return;

        previewObject.SetActive(true);
        previewObject.transform.position = targetPos;
    }

    // 放置正式建筑
    private void PlaceBuilding(Vector3 targetPos)
    {
        if (buildingPrefab == null) return;

        Instantiate(buildingPrefab, targetPos, Quaternion.identity);
    }

    // 在编辑器里修改gridDistance时自动更新半尺寸
    private void OnValidate()
    {
        gridHalfSize = gridDistance / 2f;
    }
}

关键改进说明

  • 优化网格计算:用Mathf.Round()实现精准的网格对齐,同时加入gridHalfSize让建筑中心和网格中心对齐,更符合Rust的视觉效果。
  • 预览系统:生成半透明的预览模型,实时跟随鼠标显示放置位置,玩家体验更直观。
  • 分层检测:通过LayerMask限制放置平面,避免建筑放到空中或者不该放的地方。
  • 输入处理:加入鼠标左键放置逻辑,完成从预览到放置的完整流程。
  • 编辑器友好:用OnValidate()在修改参数时自动更新辅助变量,不用进入Play模式就能看到效果。

使用注意事项

  1. 给你的地面或者放置平面设置单独的Layer,然后在组件面板里把placementLayer设为这个Layer。
  2. 确保buildingPrefab有Collider组件,不然预览的半透明材质可能不会生效。
  3. 如果你的建筑是有旋转需求的,可以再加个右键旋转预览的逻辑,这个代码里没写,你可以自己扩展~

内容的提问来源于stack exchange,提问作者RugbugRedfern

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:47:53