You need to enable JavaScript to run this app. Unity 实例化GameObject落地改Material 如何在Update中实时获取transform.position.y
优惠活动
大模型
产品
解决方案
定价
更多

Unity 实例化GameObject落地改Material 如何在Update中实时获取transform.position.y

问题根因定位

你之前的实时检测逻辑没有放在Update的常驻执行流里,大概率是把遍历列表、读取坐标的代码写在了鼠标左键点击的事件判断分支内部。这段代码只会在触发点击的那一帧执行一次,后续Cube受重力下落的过程中,因为不满足“点击左键”的触发条件,整个判断分支根本不会运行,自然无法拿到后续每帧的实时坐标,效果就和Start函数只跑一次没区别。

正确实现方式

核心调整原则

  • 所有需要跨帧使用的变量(生成的Cube列表、地面高度阈值、红色材质引用)都要定义为类的全局成员,不要写在局部方法的临时作用域里
  • 鼠标点击的分支逻辑只负责生成Cube、给随机初始位置、把生成的对象存入全局列表,绝对不要把落地检测、材质修改的代码嵌在这个分支内部
  • 遍历列表、实时读取坐标的检测逻辑要和点击判断逻辑平级放在Update的固定执行流中,保证每帧都会执行一次,读取Cube当前帧的最新位置值

参考实现代码

public class CubeSpawnLogic : MonoBehaviour
{
    // 全局跨帧使用的成员
    public List<GameObject> spawnedCubeList = new List<GameObject>();
    public float GroundLevel = 0f;
    public Material RedMat;
    public GameObject CubePrefab;
    // 生成范围参数
    public Vector2 spawnXRange = new Vector2(-6f, 6f);
    public Vector2 spawnYRange = new Vector2(8f, 15f);

    void Update()
    {
        // 1. 点击左键仅做生成逻辑
        if (Input.GetMouseButtonDown(0))
        {
            for (int i = 0; i < 10; i++)
            {
                float posX = UnityEngine.Random.Range(spawnXRange.x, spawnXRange.y);
                float posY = UnityEngine.Random.Range(spawnYRange.x, spawnYRange.y);
                GameObject spawnedCube = Instantiate(CubePrefab, new Vector3(posX, posY, 0), Quaternion.identity);
                spawnedCubeList.Add(spawnedCube);
            }
        }

        // 2. 实时检测逻辑:和点击判断平级,每帧都会执行
        // 用反向for循环遍历,方便后续需要销毁Cube时直接移除列表元素,避免迭代器报错
        for (int i = spawnedCubeList.Count - 1; i >= 0; i--)
        {
            // 提前判空,避免Cube被销毁后出现空引用异常
            if (spawnedCubeList[i] == null)
            {
                spawnedCubeList.RemoveAt(i);
                continue;
            }

            // 每帧读取当前Cube的实时y坐标做判断
            float currentY = spawnedCubeList[i].transform.position.y;
            if (currentY < GroundLevel)
            {
                Renderer cubeRender = spawnedCubeList[i].GetComponent<Renderer>();
                // 增加判断避免重复赋值材质的性能损耗
                if (cubeRender.sharedMaterial != RedMat)
                {
                    cubeRender.material = RedMat;
                }
            }
        }
    }
}
常见踩坑提醒
  • 写代码时注意大括号的闭合位置:如果遍历检测的代码块被闭合在if (Input.GetMouseButtonDown(0))的大括号内部,就会回到之前只在点击帧执行的问题
  • 读取坐标的时候不要缓存生成时的初始位置,直接每帧通过transform.position获取物理引擎计算的最新值,才能拿到下落过程中的实时y坐标
  • 遍历列表时如果要做移除元素的操作,不要用foreach语法,Unity的列表在foreach过程中修改集合会直接抛出迭代异常,反向for循环是最稳妥的遍历方式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.03 04:54:07