简体   繁体   English

检查器值无法从Unity3d中的另一个类访问

[英]Inspector value cannot access from another class in Unity3d

I have two classes. 我有两节课。 One called GameManager and another one Enemies . 一个叫GameManager ,另一个叫敌人 I have two variables in GameManager which I have changed from inspector currentLevel=1 and totalEnemy=10. 我在GameManager中有两个变量,它们已从检查器currentLevel=1totalEnemy=10.更改totalEnemy=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;
    }

I'm trying to access these two variable from Eneimes class like this; 我试图像这样从Eneimes类访问这两个变量; but everytime it gives me curLevel = 0 , but I'm expecting to get curLevel = 1 . 但是每次它都会给我curLevel = 0 ,但是我希望得到curLevel = 1 What I'm doing wrong? 我做错了什么?

// Enemies.cs

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

The line private static GameManager instance = new GameManager(); 该行的private static GameManager instance = new GameManager(); is the issue. 是问题。

When a script is attached to a GameObject , an instance of the type of the script is referenced as this inside the script. 当脚本被附接到GameObject ,该脚本的类型的实例被引用作为this脚本内部。 In other words, there can be multiple instances of same type if the same script is attached to multiple GameObject s. 换句话说,如果将相同的脚本附加到多个GameObject ,则可以存在多个相同类型的实例。

Therefore, the specific instance that have curLevel = 1 as you set in the Inspector is an instance of the type attached to the specific GameObject . 因此,您在Inspector中设置的具有curLevel = 1 的特定实例是附加到特定 GameObject的类型的实例 This means the one should be referred to as this inside the script. 这意味着在脚本中应将其称为this

If you declare a new instance of GameManager as in your code, you are basically ignoring all values in the Inspector because the static GameManager instance is pointing to a different instance than the instance you set values for in the Inspector. 如果您在代码中声明了GameManager的新实例,则基本上将忽略Inspector中的所有值,因为static GameManager instance所指向的实例与您在Inspector中为其设置值的实例不同。

In order to use the specific instance that you declared using the Inspector, you should do the following. 为了使用您使用检查器声明的特定实例,您应该执行以下操作。

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;
    }
}

Note that I changed Start() to Awake() . 请注意,我将Start()更改为Awake() This is because you are referring to values initiliased in this method from other scripts, and you cannot guarantee which Start() is called first between different MonoBehaviours in the runtime. 这是因为您是从其他脚本中引用此方法中初始化的值,并且不能保证在运行时中的不同MonoBehaviours之间首先调用哪个Start() However, Unity guarantees that Awake() is always called earlier than Start() . 但是,Unity保证总是在Start()之前调用Awake() Start() Further, it is Unity's best practice to initialise self-initialisable variables in Awake() , and initialise variables dependent on other scripts in Start() because of this execution order. 此外,Unity的最佳实践是在Awake()初始化可自我初始化的变量,并由于该执行顺序而在Start()初始化依赖于其他脚本的变量。

Lastly, there will be problems when there are multiple GameObject that has GameManager as its component in your scene. 最后,就会出现问题,当有多个GameObject是具有GameManager作为其在场景中的组成部分。 Consider a case where you have two such objects. 考虑一下您有两个这样的对象的情况。 when the scene is loaded, each of the script will call Awake() , and both of them will set private static GameManager instance; 加载场景时,每个脚本都将调用Awake() ,并且两个脚本都将设置private static GameManager instance; to each of the two this . 每两个this The result would be one is overriden by another. 结果将是一个被另一个覆盖。

You could say that you will be careful to use this script and make sure only one GameObject has this script as its component. 您可能会说,使用该脚本时要小心,并确保只有一个GameObject将此脚本作为其组件。 However, you should always write your code as if someone who do not know about your code can use it without thinking, and stupid mistakes of other people new to the project could be easily detected . 但是,您应该始终编写代码,就像不了解您的代码的人可以不经考虑就使用它,并且可以很容易地发现其他人对项目的愚蠢错误。

EDIT: 编辑:

To respond to the OP's comment, I added code to handle when this type is initialised more than once in the project. 为了回应OP的评论,我添加了代码以在项目中多次初始化此类型时进行处理。 In addition to @Kardux 's suggestion, I added Debug.LogError() because I do not want the project to silently solve things. 除了@Kardux的建议之外,我还添加了Debug.LogError()因为我不希望该项目静默地解决问题。 If a problem happens, I want to get notified of it. 如果发生问题,我想得到通知。

If you are using Singleton s frequently in your project, you might want to have a parent abstract class Singleton that handles this instance checking process for all child Singleton s, and have GameManager inherit from Singleton . 如果您在项目中经常使用Singleton ,则可能需要一个父abstract class Singleton来处理所有子Singleton的实例检查过程,并使GameManager继承自Singleton

However, use Singleton with care as it is considered a bad design pattern if misused. 但是,请谨慎使用Singleton ,因为如果滥用它,这将被视为不良的设计模式。 (And I don't know how to use it properly so I avoid using it.) (而且我不知道如何正确使用它,所以我避免使用它。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM