2017-06-19 38 views
2

我有两个类。一个叫GameManager另一个敌人。 我在游戏管理两个变量我从督察currentLevel=1totalEnemy=10.检查器值无法从Unity3d中的其他类访问

// 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 
    } 
+0

你似乎已经改变'currentLevel',你必须改变'实例' –

回答

4

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

将脚本附加到GameObject时,该脚本内的脚本类型实例被引用为this。换句话说,如果将相同的脚本附加到多个GameObject s,则可以有多个相同类型的实例。

因此,特定实例具有curLevel = 1如你在检查设定为实例附接到特定GameObject类型的。这意味着在脚本内部应该被称为this

如果声明的GameManager一个新的实例作为在你的代码,你基本上是忽略所有值的督察,因为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()。这是因为您指的是使用此方法从其他脚本启动的值,并且不能保证在运行时不同的MonoBehaviours之间首先调用哪个Start()。但是,Unity保证Awake()始终被调用的时间早于Start()。此外,由于此执行顺序,Unity是在Awake()中初始化自初始化变量的最佳实践,并根据Start()中的其他脚本初始化变量。

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

你可以说你会小心使用这个脚本,并确保只有一个GameObject这个脚本作为它的组件。但是,您应该始终编写自己的代码,就好像有人不知道您的代码可以不经过考虑就可以使用它一样,并且其他人对该项目的愚蠢错误可能是容易检测到

编辑:

要到OP的评论作出回应,我添加代码来处理时,这种类型被初始化比项目一次。除了@Kardux的建议之外,我加了Debug.LogError()因为我不想让项目默默地解决事情。如果发生问题,我想收到通知。

如果您正在使用Singleton小号经常在你的项目,你可能希望有一个父abstract class Singleton来处理这种情况下检查过程为所有的孩子Singleton s,而从SingletonGameManager继承。

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

+0

真棒解释!你也清除了我对使用Awake()和Start()的怀疑。关于在整个项目中只确定一次该脚本实例的部分,有没有想法如何实现?我使用DontDestroyOnLoad(this.gameObject);是这样的正确方法 – jquery404

+2

当使用实例时,一个好的做法是检查实例是否已经存在(如果你只需要一个作为单例方法):if(instance == null){instance = this; } else {DestroyImmediate(gameobject); }'。这可以节省你头痛的情况下,你忘记从游戏的其他场景中删除组件:) – Kardux

+0

@ jquery404我很高兴它帮助。请参阅编辑的答案。 – BrokenBacon