【问题标题】:How to check a Script for Unity Inspector null parameters and incorrect values如何检查 Unity Inspector 空参数和不正确值的脚本
【发布时间】:2019-06-16 10:57:15
【问题描述】:

我正在努力使我的 Unity 游戏代码尽可能健壮,理想情况下,我希望能够在游戏启动之前抛出异常,例如在编译时,如果 Unity Inspector 参数丢失或不正确(例如 null 或超出范围)。

目前我在Awake() 上使用AttributesUnityEngine.Assertions 的组合来检查空引用或不正确的值;在游戏启动时抛出异常(而不是在执行期间的意外点),例如:

public class PlayerMovement : MonoBehaviour
{
    [SerializeField]
    [Tooltip("Rigidbody of the Player.")]
    private Rigidbody playerRigidBody;

    [SerializeField]
    [Tooltip("Forward force of the Player.")]
    [Range(100f, 50000f)]
    private float forwardForce = 6000f;

    [SerializeField]
    [Tooltip("Sideways force of the Player.")]
    [Range(10f, 1000f)]
    private float sidewaysForce = 120f;

    private GameManager gameManager;

    void Awake()
    {
        // Cache essential references
        gameManager = GameObject.FindGameObjectWithTag("GameManager").GetComponent<GameManager>();

        // Assert that all required references are present and correct
        UnityEngine.Assertions.Assert.IsNotNull(gameManager, "Member \"gameManager\" is required.");
        UnityEngine.Assertions.Assert.IsNotNull(playerRigidBody, "Member \"Rigidbody\" is required.");
        //UnityEngine.Assertions.Assert.IsTrue(ForwardForce > 100, "\"ForwardForce\" must be greater than 100");
        //UnityEngine.Assertions.Assert.IsTrue(SidewaysForce > 10, "\"SidewaysForce\" must be greater than 10");
    }

    ...
}

这是最佳做法,还是有更好的方法在游戏启动前验证基本参数?

【问题讨论】:

  • 为什么编译时需要做呢?每次更改变量时,您都会在编辑器中获得一个名为 OnValidate() 的回调,这是标记错误的好时机,而不是当您想将构建推出门时
  • 我认为编译时间是我可以检查错误的最早时间,但我不知道 OnValidate() 回调,看起来它可能是我正在寻找的,谢谢!

标签: c# unity3d


【解决方案1】:

不是真的在编译时,但如果您想在每次在 Unity 中打开项目、重新编译代码或加载新场景时都进行检查,您可以使用 [InitializeOnLoad]SceneManager.sceneLoaded

首先有例如像

这样的界面
public interface INullReferenceChecker
{
    void CheckReferences();
}

然后有一个全局编辑器脚本,例如Assets/Editor/RunNullChecks.cs(重要的是是放在Editor所以后来被剥离了)

[InitializeOnLoad]
public class RunNullChecks
{
    public static RunNullChecks
    {
        // first of all also add a callback so it gets re-run everytime you switch a scene

        // removing it first makes sure it is only added once
        EditorSceneManager.sceneOpened -= Run;
        EditorSceneManager.sceneOpened += Run;

        Run();
    }

    private static void Run(Scene scene, LoadSceneMode mode)
    {
        Run();
    }

    public static void Run()
    {
        // here it depends a bit on your needs
        // you either can check only stuff in the Scene like
        var nullCheckers = FindObjectsOfType<INullReferenceChecker>();
        // this gets only active and enabled components!
        // or you could include all prefabs, ScriptableObjects using
        //var nullCheckers = Resources.FindObjectsOfTypeAll<INullReferenceChecker>();

        // and then let them do whatever they implemented
        foreach(var tester in nullCheckers)
        {
            tester.CheckReferences();
        }
    }
}

那么你就会有

public class PlayerMovement : MonoBehaviour, INullReferenceChecker
{
    ...

    public override void CheckReferences()
    {
        UnityEngine.Assertions.Assert.IsNotNull(gameManager, "Member \"gameManager\" is required.");
        UnityEngine.Assertions.Assert.IsNotNull(playerRigidBody, "Member \"Rigidbody\" is required.");


        // you could also simply go for
        if(!gameManager) Debug.LogErrorFormat(this, "Member \"{0}\" is required.", nameof(gameManager));
        if(!playerRigidBody) Debug.LogErrorFormat(this, "Member \"{0}\" is required.", nameof(playerRigidBody));
    }
}

另一种选择也可能是使用[ExecuteInEditMode] 属性。

这使得

  • 每次打开项目/加载场景/向场景添加新组件时都会调用Awake 方法
  • Update 每次更改场景中的内容时都会调用该方法

然后您可能会禁用某些代码块,例如在Update 中检查Application.IsPlaying 和/或Application.isEditor

【讨论】:

  • 感谢您的信息。在游戏投入生产时可以删除此脚本这一事实非常吸引人!附:我已经更新了我的问题以更清楚地说明(不一定必须在编译时,但最好在游戏启动之前,而不是在执行期间的意外点)。
  • 这当然只适用于 Unity 编辑器......如果你是这样的话,它不会抛出构建错误,因为我猜你必须坚持在 Awake 中检查它们
猜你喜欢
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 2017-12-01
  • 2019-11-27
  • 2015-05-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
相关资源
最近更新 更多