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

Unity [ExecuteAlways]特性首次编辑模式不生效问题排查

问题相关信息
  • 开发环境:Unity 2021.3.2f1 Personal 版本
  • 问题复现代码:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

[ExecuteAlways]
public class DrawOnBoxCollider : MonoBehaviour
{
    public enum DrawStates
    {
        DrawCube,
        DrawWireCube
    }

    public Transform boxColliderToDrawOn;
    [Range(0f, 1f)]
    public float colorTransparency;
    public bool draw = false;
    public DrawStates drawStates;

    private BoxCollider boxCollider = null;

    // Start is called before the first frame update
    void Start()
    {
        if (boxColliderToDrawOn != null)
        {
            boxCollider = boxColliderToDrawOn.GetComponent<BoxCollider>();
        }
        
        drawStates = DrawStates.DrawCube;
    }

    // Update is called once per frame
    void Update()
    {

    }

    private void DrawGizmosOnRunTime(Color color)
    {
        if (boxCollider != null && draw)
        {
            Gizmos.color = color;
            Matrix4x4 rotationMatrix = Matrix4x4.TRS(boxCollider.transform.position, boxCollider.transform.rotation, boxCollider.transform.lossyScale);
            Gizmos.matrix = rotationMatrix;

            switch (drawStates)
            {
                case DrawStates.DrawCube:
                    Gizmos.DrawCube(boxCollider.center, boxCollider.size);
                    break;

                case DrawStates.DrawWireCube:
                    Gizmos.DrawWireCube(boxCollider.center, boxCollider.size);
                    break;
            }
        }
    }

    private void OnDrawGizmos()
    {
        Color c = Color.red;
        c.a = colorTransparency;
        DrawGizmosOnRunTime(c);
    }
}
  • 异常现象:
    • 脚本添加[ExecuteAlways]特性后,首次打开工程时BoxCollider上无任何Gizmos绘制内容
    • 必须先进入运行模式,碰撞体上才会正常显示彩色绘制效果,退出运行模式回到编辑模式后,绘制效果也可正常显示
    • 断点调试确认:无论是否添加[ExecuteAlways]特性,OnDrawGizmos()方法内的代码都会执行,但首次编辑模式下始终无绘制内容,仅在运行一次游戏后编辑模式下的绘制才会正常生效,需要确认该现象是否为当前Unity版本的Bug。
结论

这个现象不是Unity 2021.3.2f1版本的Bug,是代码生命周期逻辑存在缺陷导致的。

原因说明

[ExecuteAlways]特性下的脚本,Start()方法在编辑模式的触发时机并不可靠:首次打开工程加载场景时,OnDrawGizmos会先于编辑模式下的Start()执行,此时用来缓存碰撞体的私有变量boxCollider还是初始值null,绘制逻辑里的判断条件if (boxCollider != null && draw)不成立,自然不会渲染任何内容。
进入运行模式时,Play模式下的Start()会被强制触发,boxCollider拿到有效引用,退出运行模式后这个缓存的引用不会被清空,所以回到编辑模式绘制就恢复正常了。
另外代码里在Start()中强制给drawStates赋值为DrawCube,会覆盖用户在Inspector中设置的绘制模式,也属于不合理的逻辑写法。

修复方案
  • 把引用获取、初始化逻辑移到OnEnable()中,[ExecuteAlways]下的OnEnable()在编辑模式域加载、脚本编译、打开工程时都会可靠触发
  • 在OnDrawGizmos中加一层兜底判断,如果boxCollider为空就重新尝试获取,避免因为引用丢失导致绘制失效
  • 去掉Start()中强制覆盖drawStates的逻辑,直接给字段设置默认值即可,不要随意覆盖用户在Inspector中的配置
  • 绘制完成后重置Gizmos矩阵,避免修改全局Gizmos状态影响场景内其他Gizmos的渲染

修复后的核心代码参考:

using UnityEngine;

[ExecuteAlways]
public class DrawOnBoxCollider : MonoBehaviour
{
    public enum DrawStates
    {
        DrawCube,
        DrawWireCube
    }

    public Transform boxColliderToDrawOn;
    [Range(0f, 1f)]
    public float colorTransparency = 0.5f;
    public bool draw = true;
    // 直接给字段设默认值,不要在生命周期方法里强制覆盖用户配置
    public DrawStates drawStates = DrawStates.DrawCube;

    private BoxCollider boxCollider = null;

    private void OnEnable()
    {
        // OnEnable在编辑模式下触发时机可靠,在这里初始化引用
        if (boxColliderToDrawOn != null)
        {
            boxCollider = boxColliderToDrawOn.GetComponent<BoxCollider>();
        }
    }

    private void DrawGizmos(Color color)
    {
        // 兜底判断,引用丢失时重新获取
        if (boxCollider == null && boxColliderToDrawOn != null)
        {
            boxCollider = boxColliderToDrawOn.GetComponent<BoxCollider>();
        }

        if (boxCollider != null && draw)
        {
            Gizmos.color = color;
            Matrix4x4 rotationMatrix = Matrix4x4.TRS(boxCollider.transform.position, boxCollider.transform.rotation, boxCollider.transform.lossyScale);
            Gizmos.matrix = rotationMatrix;

            switch (drawStates)
            {
                case DrawStates.DrawCube:
                    Gizmos.DrawCube(boxCollider.center, boxCollider.size);
                    break;
                case DrawStates.DrawWireCube:
                    Gizmos.DrawWireCube(boxCollider.center, boxCollider.size);
                    break;
            }
            // 绘制完重置Gizmos矩阵,避免影响其他Gizmos绘制
            Gizmos.matrix = Matrix4x4.identity;
        }
    }

    private void OnDrawGizmos()
    {
        Color c = Color.red;
        c.a = colorTransparency;
        DrawGizmos(c);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 15:45:41