我有两节课。一个叫GameManager,另一个叫敌人。
我在GameManager中有两个变量,它们已从检查器currentLevel=1totalEnemy=10.更改为

// GameManager.cs
    private static GameManager instance = new GameManager();
    public static GameManager get(){ return instance; }

    public int currentLevel;
    public int curLevel { get; set; }
    public int totalEnemy;
    public int totLevel { get; set; }


    void Start () {
        curLevel = currentLevel;
        totLevel = totalEnemy;
    }


我试图像这样从Eneimes类访问这两个变量;但每次它都会给我curLevel = 0,但我希望得到curLevel = 1。我做错了什么?

// Enemies.cs

    void Start () {
        Debug.Log (GameManager.get().curLevel); // always output = 0
    }

最佳答案

问题是private static GameManager instance = new GameManager();行。

将脚本附加到GameObject时,该脚本类型的实例在脚本内称为this。换句话说,如果将同一脚本附加到多个GameObject,则可以存在多个相同类型的实例。

因此,在检查器中设置的具有curLevel = 1的特定实例是附加到特定GameObject的类型的实例。这意味着该脚本在脚本中应称为this

如果在代码中声明GameManager的新实例,则基本上会忽略Inspector中的所有值,因为static GameManager instance所指向的实例与您在Inspector中为其设置的实例不同。

为了使用您使用检查器声明的特定实例,您应该执行以下操作。

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

public class GameManager : MonoBehaviour
{
    private static GameManager instance;
    public static GameManager get() { return instance; }

    public int currentLevel;
    public int curLevel { get; set; }
    public int totalEnemy;
    public int totLevel { get; set; }

    void Awake()
    {
       if (instance == null)
       {
          instance = this;
       }
       else
       {
          Debug.LogError(string.Format("GameManager.Awake(): More than one instances of this type {0} is being initialised but it's meant to be Singleton and should not be initialised twice. It is currently being initialised under the GameObject {1}.", this.GetType(), this.gameObject.name));
          Destroy(gameObject);
       }

        curLevel = currentLevel;
        totLevel = totalEnemy;
    }
}


请注意,我将Start()更改为Awake()。这是因为您是从其他脚本中引用此方法中初始化的值,并且不能保证在运行时中,在不同的Start()之间首先调用哪个MonoBehaviours。但是,Unity保证总是在Awake()之前调用Start()。此外,Unity的最佳实践是在Awake()中初始化可自我初始化的变量,并由于该执行顺序而在Start()中初始化依赖于其他脚本的变量。

最后,当场景中有多个以GameObject作为其组成部分的GameManager时,将会出现问题。考虑一下您有两个这样的对象的情况。加载场景时,每个脚本都将调用Awake(),并且两个脚本都将private static GameManager instance;设置为两个this的每个。结果将是一个被另一个覆盖。

您可能会说,使用此脚本时要小心,并确保只有一个GameObject将此脚本作为其组件。但是,您应该始终编写代码,就像不了解您的代码的人可以不经考虑就使用它,并且可以很容易地检测到其他新人的愚蠢错误。

编辑:

为了回应OP的评论,我添加了代码以在项目中多次初始化此类型时进行处理。除了@Kardux的建议外,我添加了Debug.LogError(),因为我不希望该项目静默地解决问题。如果发生问题,我想得到通知。

如果您在项目中经常使用Singleton,则可能希望有一个父abstract class Singleton处理所有子Singleton的此实例检查过程,并让GameManager继承自Singleton

但是,请小心使用Singleton,因为如果使用不当,它会被认为是不好的设计模式。 (而且我不知道如何正确使用它,所以我避免使用它。)

关于c# - 检查器值无法从Unity3d中的另一个类访问,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44623070/

10-09 19:39