2014-11-08 221 views
0

嗨我是新来的Unity游戏引擎,我正在创建一个3D射击游戏。在等级1中,我想在一定时间内射击5个敌人,比如30秒。在完成1级后,我想进入等级2,我的总敌人数为10,并且想要在60秒内杀死它,如果失败,游戏结束。我为它写了一些脚本,但它有点作用,但它并不完美,因为在开始第2级之后,游戏变得缓慢,并且在游戏结束后,第2级再次重新启动,但不是默认值10个敌人,而是从没有。在比赛结束时达到。我的游戏需要一些想法和良好的逻辑和脚本。这是我的代码。需要我的Android游戏的逻辑

public class Status : MonoBehaviour 
{ 

    public static int TotalZombies=5; 
    public static float timeLeft=25.0f; 

// destry this game object. 
      Destroy (this.gameObject); 
      TotalZombies--; 
      } 

,这里是我的地方,我处理我的水平和时间等其他脚本

using UnityEngine; 
using System.Collections; 

public class Generate : MonoBehaviour { 
    public GUIText Zombiesobject; 
    public string zombiesscore; 
    public GUIText countdown; 
    // Use this for initialization 
    void Start() { 

    } 

    // Update is called once per frame 
    void Update() { 
     zombiesscore = "Zombies Left: " + Status.TotalZombies.ToString(); 
     Zombiesobject.text = (zombiesscore); 

     Status.timeLeft -= Time.deltaTime; 
     if (Status.timeLeft <= 0.0f && Status.TotalZombies > 0) 
     { 
      countdown.text = "Game Over"; 
      Application.LoadLevel(Application.loadedLevel); 
} 
     else if (Status.timeLeft <= 10.0f && Status.TotalZombies > 0) 
     { 
      countdown.text = "Time left = " + (int)Status.timeLeft + " seconds" + " \n You are running out of time!"; 
     } 
     else if (Status.timeLeft > 0.0f && Status.TotalZombies <= 0) { 
       countdown.text = "You win!"; 
       Application.LoadLevel("level 2"); 
       Status.TotalZombies=10; 
       Status.timeLeft=59.0f; 
     } 
     else 
     { 
      countdown.text = "Time left = " + (int)Status.timeLeft + " seconds"; 
     } 
    } 
} 
+0

它也会在游戏结束后挂起。 – user3866627 2014-11-08 12:03:17

回答

1

你的问题是,你使用static变量。 static完全像全局变量。唯一的区别是你需要通过一个Class名称来访问它们。

那究竟是什么意思?当你加载你的游戏,并且当这个类本身被加载时,静态变量被创建和初始化。在你的情况下,它是TotalZombies设置为5timeLeft25f

但是只要你的游戏运行,这些变量就会一直存在,并且永远不会被重新初始化。即使你做了Application.LoadLevel这些变量和它们的值仍然存在。

这意味着如果你改变这些变量,并重新加载你的水平TotalZombiestimeLeft仍然有他们的最后值。

因此,我鼓励永远不要使用static变量。他们很容易引入难以发现的错误。让我们假设对代码进行简单修复。

您还为您的Start()方法添加初始化。例如,在您添加的Status类中。

void Start() { 
    TotalZombies = 5; 
    timeLeft  = 25.0f; 
} 

在你的情况下,它可以完全解决问题,但你也可以说这只是偶然或运气。

在Unity中,不存在调用Start()的顺序。例如,在加载场景时,可能会发生以下情况:您的Generate类中的Start方法首先被调用。如果您在Start中使用Status.TotalZombiesStatus.timeleft初始化Generate中的某些内容,则仍然存在您的初始化错误,因为它使用了上一次运行的变量。问题是Unity有时可能会首先在Generate.Start()之前首先执行Status.Start()。这将导致只有sometimes发生并且极难调试的错误。

如果您知道上述内容,您也可以将您的初始化设置为Awake方法。因为在任何Start方法之前将调用Awake方法。所以这将是一个更好的解决方案。

但还存在其他问题。例如,让我们看看你的Generate.Update()方法。例如,您直接在Update方法中执行Status.timeLeft -= Time.deltaTime;。但是,例如,如果您的游戏中有多个GameObjects,其中包含Generate组件,则表示timeLeft将在单个帧中多次减少。如果您有两个组件,则意味着您的时间将快两倍。

因此,即使把初始化成StartAwake可以修复一些bug,但你仍然有不同的问题static小号

这就是为什么我鼓励不使用static根本原因。那么如何解决这个问题?您应该创建一个类的属性,而不是静态的。最重要的是,你应该让所有属性只能从你自己的班级中设置。这也对其他代码有影响。例如,您不能从Generate中减少timeLeft属性。这听起来像是一个缺点,但是它会迫使你想如何正确地改变timeLeft。在你的情况下,你并不是真的希望任何地方的任何班级都能改变timeLeft。这是一个应该不断缩短的时间,多次缩短它只是一个错误。结果是。您的Status课程只应更改Update中的timeLeftTotalZombies也是如此。最好是只有像IncrementTotalZombiesDecrementTotalZombies这样的方法,而不是做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--; 
    } 
} 

现在IncreaseTotalZombiesDecreaseTotalZombies听起来像是开销,但你可以做很多额外的检查在这里。例如检查计数器是否小于零。因为当它的时候,你的代码中有一个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 ZombiesStart Time。在这个框中,你现在可以输入多少僵尸或你的关卡应该有多少开始时间。这些值的默认值是525。但是这些价值并没有被用于加载你的关卡。也可以在您的关卡装载时应用这些值,将您的Awake方法更改为。现在

void Awake() { 
    this.TotalZombies = this._StartZombies; 
    this.TimeLeft  = this._StartTime; 
} 

this.TotalZombiesthis.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 0Element 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”之前。

+0

谢谢...有没有什么方法可以在Generate class中控制所有的游戏关卡以及我的敌人的数量和时间?就像在进入等级3之前,我想把我的敌人改变为15和15.0f? – user3866627 2014-11-08 13:40:42

+0

@user我在最后添加了它。最好的方法是,如果你不使用静态并从其他值启动它们,比如'_StartZombies'。通过这种方式,您可以从Unity IDE配置时间和僵尸,而不是通过代码进行设置。通过初始化设置代码并仍然使用静态不是一个好方法。因为在每次加载时,您的“唤醒”或“开始”将其重置为默认值。它只会在'LoadLevel'之前设置静态值并且不会用'Start'或'Awake'初始化值。 – 2014-11-08 13:46:48

+0

对不同的级别使用不同的生成类是一个好主意吗?像生成1级,生成2级,在那里我分别设定我的敌人和时间? – user3866627 2014-11-08 13:49:53