统一评分系统的创建

Creation of a score system in unity

我目前正在开发一个简单的 2D 游戏,以学习有关游戏开发的许多知识。

尽管如此,我在创建评分系统时遇到了一些问题。

我想每秒更新一次比分,每秒加1分,比赛结束后停止计时

我开始写这个

public class scoremanager : MonoBehaviour {

    public int score;
    public GUIText distance;

    void Start () {
        score = 0;
    }

    void Update () {
        StartCoroutine(updateScoreManager(1f, 1));
        distance.text = score.ToString();
    }

    IEnumerator updateScoreManager(float totalTime, int amount) {
        score += amount; 
        yield return new WaitForSeconds (totalTime);
    }
}

问题是 GUIText 中没有显示任何内容,所以我不知道它是否有效。游戏结束后如何停止计数?

The issues are that nothing shows up in the GUIText so I don't know if it works

会发生什么?它总是为零还是什么都不显示?如果没有 - 检查坐标、图层等以确保您正确定位它。参考http://docs.unity3d.com/Manual/class-GUIText.html

And how can I stop the count when the game is over?

在游戏结束事件中使用 StopCoroutine(updateScoreManager),并且不要忘记将分数设置为零。

其实是说你的代码设计的不好。实现 StateObserverComponent 模式会很棒。使用状态,您可以实现 Game、GameOver 等游戏状态。使用 Observer,您可以通知您的分数组件。使用组件,您可以通过将评分逻辑放置到评分组件来满足单一责任原则。

至少考虑单独的开始游戏初始化、更新组件和游戏结束逻辑。

我将跳过有关您正在实施的模式的讲座,因为我不知道您的其余代码是什么样子,但更新问题的根源在这里:

IEnumerator updateScoreManager(float totalTime, int amount)
    {
        score += amount;
        yield return new WaitForSeconds(totalTime);

    }

实际上,当我 运行 处理这类问题时,我将失败的逻辑与源应用程序分开,以帮助减少噪音。

因此,当我为您的算法制作原型时(下面的代码)发生的事情是得分始终为零,因为 StartCoroutine 应该使用 updateScoreManager 的 return 值来进行更新,而 .Update() 是打电话。

如果我的原型看起来与您尝试实现此代码的方式相匹配,那么我可以post稍后我将如何解决这个问题。

但基本上,不是 returning IEnumerator return 一个更新分数的 int,这可能会让你解决这个问题。

除非你能在代码的其他地方描述 use-case 你需要 IEnumerator 的地方?

执行原型:

class Program
{
    static void Main(string[] args)
    {
        Ans34612672 Ans34612672 = new Ans34612672();
        Ans34612672.Execute();
        Console.ReadKey();
    }
}

原型包装器Class:

public class Ans34612672
{
    public Ans34612672()
    {

    }

    public bool Execute()
    {
        bool retValue = false;
        scoremanager Manager = new scoremanager();
        Manager.Start();
        while(Manager.score < 20)
        {
            Manager.Update();
        }
        Console.WriteLine(Manager.distance);
        Console.ReadKey();
        return retValue;
    }

}

原型Class是:

public class scoremanager : MonoBehaviour
{

    public int score;
    public GUIText distance;

    public void Start()
    {
        score = 0;
        distance = new GUIText();
    }

    public void Update()
    {
        IEnumerator UpdateResults = updateScoreManager(1f, 1);
        StartCoroutine(UpdateResults);
        distance.text = score.ToString();

    }

    private void StartCoroutine(IEnumerator enumerator)
    {
        //Implement Logic
    }

    IEnumerator updateScoreManager(float totalTime, int amount)
    {
        score += amount;
        yield return new WaitForSeconds(totalTime);

    }
}

internal class WaitForSeconds
{
    private float totalTime;

    public WaitForSeconds(float totalTime)
    {
        this.totalTime = totalTime;
    }
}

public class GUIText
{
    internal string text;
}

public class MonoBehaviour
{
}

首先,我认为您应该使用 uGUI,因为这是 Unity 现在为 UI 接受的解决方案:http://blogs.unity3d.com/2014/05/28/overview-of-the-new-ui-system/

我真的不能说你的 GUIText 有什么问题,因为我不知道位置是否关闭或其他什么,但我可以告诉你如何更好地管理计数。

您不需要使用更新功能,使用更新功能违背了使用协程更新文本的目的。使用协程可以让您控制何时开始更新以及何时停止更新。因此,一种解决方案是完全摆脱更新功能,以便更好地控制它:

public class scoremanager : MonoBehaviour {

    public int score;
    public GUIText distance;

    private Coroutine scoreCoroutine;

    void Start () {
        score = 0;
        scoreCoroutine = StartCoroutine(updateScoreManager(1f, 1));
    }

    IEnumerator updateScoreManager(float totalTime, int amount) {
        while(true) {
            score += amount; 
            distance.text = score.ToString();
            yield return new WaitForSeconds (totalTime);
        }
    }

    // example of ending game
    void EndGame() {
        StopCoroutine(scoreCoroutine);
        scoreCoroutine = null;
    }
}

这可能看起来很奇怪(为什么我要使用无限循环)?但这就是协程的美妙之处,您可以编写这样的代码,因为 yield 语句允许您从代码中 return 并稍后返回到同一位置。通常 while 循环会导致您的游戏崩溃,但是 yield 语句让您创建一个 time while 循环!

希望对您有所帮助!

我在您的代码中发现了一些小问题。先覆盖一下吧。

  • 您正在 Update 中呼叫 Coroutine,延迟时间为 1 秒。这意味着您的 Coroutine 每秒执行 30 或 60 次。
  • 您也在 Update 中分配文本。这可能是它刷新文本的原因(对此不确定)
  • 在您的 Coroutine 中,您的延迟即 WaitForSeconds 在这里没有用,因为在那行代码之后没有发生任何事情。

我正在修改你的确切代码,这样你就能明白你想要的也可以通过这个来实现:)

public class scoremanager : MonoBehaviour {

    public int score;
    public GUIText distance;
    public bool isGameOver = false;

    void Start () {
        score = 0;
        StartCoroutine(updateScoreManager(1f, 1));
    }

    void Update () {

    }

    IEnumerator updateScoreManager(float totalTime, int amount) {
        while(!isGameOver){
            score += amount; 
            distance.text = score.ToString();
            yield return new WaitForSeconds (totalTime);
        }
    }
}

有什么变化...

  • Update 中没有代码。
  • 只调用一次Coroutine
  • Coroutine 中,它正在改变 scoredistance 两者,每 totalTime 秒一次。直到 isGameOver 标志为 false。游戏结束后 true

我想您的问题的简单解决方案是 InvokeRepeating

//Invokes the method methodName in time seconds, then repeatedly every repeatRate seconds.
public void InvokeRepeating(string methodName, float time, float repeatRate);

所以你转换后的代码是

public class 得分管理器:MonoBehaviour {

public int score;
public GUIText distance;

void Start () {
   InvokeRepeating("updateScoreManager",1f,1f);
}

void Update () {
    distance.text = score.ToString();
}

void updateScoreManager() {
    score += 1; 
}