你的问题是,你使用static
变量。 static
完全像全局变量。唯一的区别是你需要通过一个Class名称来访问它们。
那究竟是什么意思?当你加载你的游戏,并且当这个类本身被加载时,静态变量被创建和初始化。在你的情况下,它是TotalZombies
设置为5
和timeLeft
到25f
。
但是只要你的游戏运行,这些变量就会一直存在,并且永远不会被重新初始化。即使你做了Application.LoadLevel
这些变量和它们的值仍然存在。
这意味着如果你改变这些变量,并重新加载你的水平TotalZombies
和timeLeft
仍然有他们的最后值。
因此,我鼓励永远不要使用static
变量。他们很容易引入难以发现的错误。让我们假设对代码进行简单修复。
您还为您的Start()
方法添加初始化。例如,在您添加的Status
类中。
void Start() {
TotalZombies = 5;
timeLeft = 25.0f;
}
在你的情况下,它可以完全解决问题,但你也可以说这只是偶然或运气。
在Unity中,不存在调用Start()
的顺序。例如,在加载场景时,可能会发生以下情况:您的Generate
类中的Start
方法首先被调用。如果您在Start
中使用Status.TotalZombies
或Status.timeleft
初始化Generate
中的某些内容,则仍然存在您的初始化错误,因为它使用了上一次运行的变量。问题是Unity有时可能会首先在Generate.Start()
之前首先执行Status.Start()
。这将导致只有sometimes
发生并且极难调试的错误。
如果您知道上述内容,您也可以将您的初始化设置为Awake
方法。因为在任何Start
方法之前将调用Awake
方法。所以这将是一个更好的解决方案。
但还存在其他问题。例如,让我们看看你的Generate.Update()
方法。例如,您直接在Update
方法中执行Status.timeLeft -= Time.deltaTime;
。但是,例如,如果您的游戏中有多个GameObjects
,其中包含Generate
组件,则表示timeLeft
将在单个帧中多次减少。如果您有两个组件,则意味着您的时间将快两倍。
因此,即使把初始化成Start
或Awake
可以修复一些bug,但你仍然有不同的问题static
小号
这就是为什么我鼓励不使用static
根本原因。那么如何解决这个问题?您应该创建一个类的属性,而不是静态的。最重要的是,你应该让所有属性只能从你自己的班级中设置。这也对其他代码有影响。例如,您不能从Generate
中减少timeLeft
属性。这听起来像是一个缺点,但是它会迫使你想如何正确地改变timeLeft
。在你的情况下,你并不是真的希望任何地方的任何班级都能改变timeLeft
。这是一个应该不断缩短的时间,多次缩短它只是一个错误。结果是。您的Status
课程只应更改Update
中的timeLeft
。 TotalZombies
也是如此。最好是只有像IncrementTotalZombies
和DecrementTotalZombies
这样的方法,而不是做Status.TotalZombies++
等等。例如您Status
类现在应该像
public class Status : MonoBehaviour {
public int TotalZombies { get; private set; }
public float TimeLeft { get; private set; }
void Awake() {
this.TotalZombies = 5;
this.TimeLeft = 25f;
}
void Update() {
this.TimeLeft -= Time.deltaTime;
}
public void IncreaseTotalZombies() {
this.TotalZombies++;
}
public void DecreaseTotalZombies() {
if (this.TotalZombies <= 0) {
throw new ApplicationException("Cannot decrease TotalZombies. Already 0. Possible Bug in your code.");
}
this.TotalZombies--;
}
}
现在IncreaseTotalZombies
或DecreaseTotalZombies
听起来像是开销,但你可以做很多额外的检查在这里。例如检查计数器是否小于零。因为当它的时候,你的代码中有一个bug。例如意外增加2个TotalZombies,或者其他地方减少2个,等等。你也可以实现一个MaxTotalZombies
属性,确保你永远不会获得更多的僵尸定义。如果发生这种情况,它会抛出一个异常,将它直接指向你的代码。
识别错误也很容易。因为连续增加两次看起来是错误的。
status.IncreaTotalZombies();
status.IncreaTotalZombies();
,其中下面的代码可以直接看的权利
Status.TotalZombies += 2;
但是,如果你做了以上的变化,你会看到你当前Status.TotalZombies
将不再工作。您还必须更改如何获得Status
课程的实例。为此,假设您在Unity中创建一个名为Status
的GameObject。然后在你的Generate
类中添加以下内容。
private Status status;
void Awake() {
this.status = GameObject.Find("Status").GetComponent<Status>();
}
现在你可以用status.IncreaseTotalZombies()
取代Status.TotalZombies++
等。如果您只想获取值,您仍然可以编写status.TimeLeft
,但设置值status.TimeLeft -= Time.deltaTime
现在将引发错误。你不需要再设置它,因为这是Status
类已经在他的Update
方法中已经处理的行为。
现在在你的代码中加入Generate
这个代码。
Application.LoadLevel("level 2");
Status.TotalZombies=10;
Status.timeLeft=59.0f;
这没有像预期的那样工作。因为当你打电话给Application.LoadLevel()
时,你的新场景被调用,它后面的线条从未被调用过。你可以解决这个问题,就是改变顺序。
Status.TotalZombies=10;
Status.timeLeft=59.0f;
Application.LoadLevel("level 2");
因为您的状态static
值通过加载持续存在。但整个方法仍然不是很好。问题是你在代码中硬编码值。看来你需要不同数量的僵尸和时间每个级别。如果你想要的话,你可以添加属性到你的Status
类,初始化你的变量,这些变量可以通过你的Unity IDE设置。例如,将以下属性添加到Status
类中。
public int _StartZombies = 5;
public float _StartTime = 25f;
如果你在你的IDE现在添加到您的Status
类两个文本框会出现一个名为Start Zombies
和Start Time
。在这个框中,你现在可以输入多少僵尸或你的关卡应该有多少开始时间。这些值的默认值是5
和25
。但是这些价值并没有被用于加载你的关卡。也可以在您的关卡装载时应用这些值,将您的Awake
方法更改为。现在
void Awake() {
this.TotalZombies = this._StartZombies;
this.TimeLeft = this._StartTime;
}
this.TotalZombies
和this.TimeLeft
总是让您在IDE中配置的值。你现在唯一需要做的就是写。
Application.LoadLevel("SomeLevel");
而且你可以通过IDE配置僵尸的数量和时间!这也意味着你现在有可重用的组件。而且你配置了它所属的地方!
您还描述了您需要不同的条件来加载新级别。例如,如果用户能够在特定时间内杀死所有僵尸,他将直接跳到级别3而不是级别2,依此类推。那么如何在不创建许多特殊类的情况下添加这些?
首先,你需要一个自己只有一个类的数据。在你的情况下,你需要一个特定的时间和一个定义哪个级别被加载。所以你可以写这样的东西。
[System.Serializable]
public class LoadLevelData {
public float TimeLeft;
public string LoadLevel;
}
但在这种逻辑属于Status
类我看来,所以你现在要做的是以下内容添加到这个类。
public LoadLevelData[] _NextLevels;
只要您将其添加到您的代码。在Unity IDE中,您将看到带有“光标”的“下一级”。您现在可以展开此光标,并且会出现一个Size
字段。你现在可以例如写入2,它给你Element 0
和Element 1
。因此,Unity使您能够创建一个对象数组,并且您可以根据需要使用您想要的任何值创建任意数量的条目!
现在,您可以用这种方法编写LoadNextLevel
方法。
public void LoadNextLevel() {
foreach (var level in this._NextLevels) {
if (level.TimeLeft > this.TimeLeft) {
Application.LoadLevel(level.LoadLevel);
}
}
}
现在你可以在Unity IDE
Element 0:
Time Left -> 20
Next Level -> "Level 3"
Element 1:
Time Left -> 10
Next Level -> "Level 2"
配置你只需要调用status.LoadNextLevel()
当你的游戏结束了。您可以配置IDE中的所有内容。另请注意。您填充_NextLevel数组的顺序非常重要。在这种情况下,“剩余时间” - > 20必须在“10”之前。
它也会在游戏结束后挂起。 – user3866627 2014-11-08 12:03:17