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

3D房屋预制体无论是否重叠均无法显示透明红/绿色的问题求助

建筑放置项目中房屋预制体材质切换异常问题解决

问题描述

我正在开发一个建筑放置项目,所有物体都带有Rigidbody和Box Collider组件,仅房屋预制体包含子物体。当前脚本在Unity默认3D物体(胶囊体、球体、立方体)上运行正常——拖动这些物体与已放置的房屋重叠时,物体会变为透明红色;移至地面时变为透明绿色。但房屋预制体无论是否与其他物体重叠,都无法切换至透明红/绿色材质。

当前使用脚本

BuildingManager 脚本

public class BuildingManager : MonoBehaviour
{
      private GameObject pendingObject;
      [SerializeField] private Material[] materials;
      public bool canPlace;

void Update()
{
     if (pendingObject != null)
     {
         UpDateMaterials();
          
      pendingObject.transform.position = pos;

         if (Input.GetMouseButtonDown(0) && canPlace)
         {
             PlaceObject();
         }
     }
}

public void PlaceObject()
{
     pendingObject.GetComponent<MeshRenderer>().material = materials[2];
     pendingObject = null;
}

public void UpDateMaterials()
{
     if (canPlace)
     {
         pendingObject.GetComponent<MeshRenderer>().material = materials[0];
     
     }
     if (!canPlace)
     {
         pendingObject.GetComponent<MeshRenderer>().material = materials[1];
     
     }
}
}

CheckPlacement 脚本

public class CheckPlacement : MonoBehaviour
{
    BuildingManager buildingManager;

    void Start()
    {
        buildingManager = GameObject.Find("BuildingManager").GetComponent<BuildingManager>();
    }

   private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Building"))
        {
            Debug.Log("Can't Place Building");
            buildingManager.canPlace = false;
        }
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.gameObject.CompareTag("Building"))
        {
            Debug.Log("Can Place Building");
             buildingManager.canPlace = true;
       }
    }
}

问题原因分析

  1. MeshRenderer位置问题:房屋预制体的MeshRenderer通常挂载在子物体上,而当前脚本仅尝试获取根物体的MeshRenderer,根物体无此组件,导致材质切换代码无效。
  2. 触发检测覆盖不全:仅依赖OnTriggerEnter和OnTriggerExit,若待放置物体长时间处于重叠状态,可能出现状态异常。
  3. 初始化缺失:未在放置房屋前初始化canPlace状态,可能导致初始状态错误。

解决方案

1. 遍历所有子物体修改材质

修改BuildingManager中的方法,遍历待放置物体的所有MeshRenderer(包括子物体)进行材质设置:

public class BuildingManager : MonoBehaviour
{
      private GameObject pendingObject;
      [SerializeField] private Material[] materials;
      public bool canPlace;

void Update()
{
     if (pendingObject != null)
     {
         UpDateMaterials();
          
      pendingObject.transform.position = pos;

         if (Input.GetMouseButtonDown(0) && canPlace)
         {
             PlaceObject();
         }
     }
}

public void PlaceObject()
{
    SetMaterialForAllRenderers(materials[2]);
    pendingObject = null;
}

public void UpDateMaterials()
{
    if (canPlace)
    {
        SetMaterialForAllRenderers(materials[0]);
    }
    else
    {
        SetMaterialForAllRenderers(materials[1]);
    }
}

// 新增方法:遍历所有MeshRenderer设置材质
private void SetMaterialForAllRenderers(Material targetMat)
{
    MeshRenderer[] renderers = pendingObject.GetComponentsInChildren<MeshRenderer>(true);
    foreach (var renderer in renderers)
    {
        renderer.material = targetMat;
    }
}

// 新增:设置待放置物体时初始化状态
public void SetPendingObject(GameObject obj)
{
    pendingObject = obj;
    canPlace = true;
}
}

2. 完善触发检测逻辑

修改CheckPlacement脚本,添加OnTriggerStay确保状态实时更新:

public class CheckPlacement : MonoBehaviour
{
    BuildingManager buildingManager;

    void Start()
    {
        buildingManager = GameObject.Find("BuildingManager").GetComponent<BuildingManager>();
    }

   private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Building"))
        {
            Debug.Log("Can't Place Building");
            buildingManager.canPlace = false;
        }
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.gameObject.CompareTag("Building"))
        {
            Debug.Log("Can Place Building");
             buildingManager.canPlace = true;
       }
    }

    // 新增:持续检测重叠状态
    private void OnTriggerStay(Collider other)
    {
        if (other.gameObject.CompareTag("Building"))
        {
            buildingManager.canPlace = false;
        }
    }
}

3. 检查组件挂载与设置

  • 将CheckPlacement脚本挂载到待放置房屋预制体的根物体上。
  • 确保根物体的Box Collider勾选IsTrigger(触发检测需要)。
  • 待放置物体的Rigidbody设置为Kinematic(避免物理引擎干扰拖动)。
  • 所有已放置的建筑物体标签设置为"Building"。

内容的提问来源于stack exchange,提问作者Kıvanç Cantimur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:37:02