我有两节课。一个叫做 GameManager ,另一个叫 Enemies 。
我在 GameManager 中有两个变量,我从检查员ID Match ID New ID
Zrecruit_376840000000415007 Zrecruit_376840000000367020 = 5782
Zrecruit_376840000000215296 Zrecruit_376840000000375036 = 5783
Zrecruit_376840000000217195 Zrecruit_376840000000389001 = 5784
Zrecruit_376840000000218111 Zrecruit_376840000000369168 = 5785
Zrecruit_376840000000219665 Zrecruit_376840000000392001 = 5786
Zrecruit_376840000000222030 Zrecruit_376840000000410013 = 5787
Zrecruit_376840000000226008 Zrecruit_376840000000432013 = 5788
Zrecruit_376840000000227079 Zrecruit_376840000000415007 = 5789
和currentLevel=1
更改了
totalEnemy=10.
我试图像这样从 Eneimes 类中访问这两个变量;但每次它都给我// 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;
}
,但我希望得到curLevel = 0
。我做错了什么?
curLevel = 1
答案 0 :(得分:4)
问题private static GameManager instance = new GameManager();
是问题。
当脚本附加到GameObject
时,脚本类型的实例在脚本中被引用为this
。换句话说,如果将相同的脚本附加到多个GameObject
,则可能存在多个相同类型的实例。
因此,在检查器中设置的 具有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()
。这是因为您指的是此方法中从其他脚本启动的值,并且您无法保证在运行时的不同Start()
之间首先调用哪个MonoBehaviours
。但是,Unity保证Awake()
始终比Start()
更早被调用。此外,在Awake()
中初始化自我初始化变量是Unity的最佳实践,并且由于此执行顺序而初始化依赖于Start()
中其他脚本的变量。
最后,如果有多个GameObject
在您的场景中有GameManager
作为其组件,则会出现问题。考虑一个你有两个这样的对象的情况。加载场景时,每个脚本都会调用Awake()
,并且两个脚本都会将private static GameManager instance;
设置为两个this
中的每一个。结果是一个被另一个覆盖。
您可以说您将小心使用此脚本,并确保只有一个GameObject
将此脚本作为其组件。但是,您应该始终编写代码,就像不了解您的代码的人可以不假思索地使用它一样,而对于项目新手的其他人的愚蠢错误可以 轻松检测到 强>
编辑:
为了回应OP的评论,我添加了代码来处理在项目中多次初始化此类型的时间。除@Kardux的建议外,我添加了Debug.LogError()
,因为我不希望项目 默默地 解决问题。如果出现问题,我希望得到通知。
如果您在项目中频繁使用Singleton
,则可能希望父abstract class Singleton
处理所有子Singleton
的此实例检查过程,并GameManager
Singleton
1}}继承自Singleton
。
但是,请谨慎使用endif
,因为如果误用,它会被视为糟糕的设计模式。 (而且我不知道如何正确使用它,所以我避免使用它。)