简体   繁体   中英

How can I update my GUI score one point at a time?

If a player receives X amount of points for doing something in my game I want the scoreboard to update showing each number from 0 - X very briefly. I'm going for an analog style scoring system like those old clocks where you can watch the numbers change, except the change will happen quickly because hundreds of points can be added at the same time.

Currently, X amount of points are updated instantly when points are awarded:

/****************************** Platform Collision ***************************/

void OnCollisionEnter2D(Collision2D coll)
    {
        foreach(ContactPoint2D contact in coll.contacts)
        {   
            newPlayerHeight = transform.position.y;

            // Don't count the first jump
            if(newPlayerHeight < 0){
                newPlayerHeight = 0;
            }

            // If the player jumps down, don't reduce points
            // Add a tolerance for variable collision positions on same platform
            if(newPlayerHeight < oldPlayerHeight + -0.05f){
                newPlayerHeight = oldPlayerHeight;
            }

            // Send the height to the Score class
            Score.SP.updateScore(newPlayerHeight);

            oldPlayerHeight = newPlayerHeight;
        }
    }

/******************************* Score class *********************************/

public void updateScore (float newScore)
    {
        // Display GUI score
        score = (int)(newScore * 76);
        guiText.text = "Score" + score;

    }

I messed around with a for-loop to try and achieve this but got nowhere close.

I just created this code, which solves your problem. I am currently using it in my own game.

The main idea of the ScoreManager class is to keep tract of the score and update it every frame. It uses a Stack to keep track of the score to be added, that way we don't have a magic number increasing the score.

So when the player earns a new point just call the addScore() function then the ScoreManager class will handle the updating all by itself.

It will have a thread always running which will increase from currentScore to newScore digit by digit, that way the change is observable by users like you wanted.

The thread was added to reduce the "lag" you are experiencing in the other question you posted : Why is my game lagging huge when I call a method?

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

public class ScoreManager : MonoBehaviour 
{
    public GUIText score;

    private int currentScore = 0;
    public int scoreToUpdate = 0;

    private Stack<int> stack;

    private Thread t1;
    private bool isDone = false;

    void Awake() 
    {
        stack = new Stack<int>();
        t1 = new Thread(updateScore);
        t1.Start();
    }

    private void updateScore()
    {
        while(true)
        {
            if(stack.Count > 0)
            {
                int newScore = stack.Pop() + currentScore;

                for(int i = currentScore; i <= newScore; i++)
                {
                    scoreToUpdate = i;
                    Thread.Sleep(100); // Change this number if it is too slow.
                }

                currentScore = scoreToUpdate;
            }

            if(isDone)
                return;
        }
    }

    void Update() 
    {
        score.text = scoreToUpdate + "";
    }

    public void addScore(int point)
    {
        stack.Push(point);
    }

    public void OnApplicationQuit()
    {
        isDone = true;
        t1.Abort();
    }
}

I plan to turn this code into a Singleton so that there is only one instance of this class in my game. I highly recommend you do the same.

Have you tried using a Unity coroutine? It could be easier to implement, starting a coroutine and letting the frame update between each increase in the score would be a simple way to get things going.

A coroutine allows access to yield return null this will wait until the end of the current frame to continue with the function.

...
StartCoroutine(AddtoScore(ValuetoAdd));
...
...
public IEnumerator AddtoScore(int value) {
    for(int i = 0; i < value; i++) {
        currentScore++;
        guiText.text = "Score: " + currentScore;
        yield return null;
    }
}
...

However the downside of this is that if you score again while it is adding points it may create some graphical problems.

On the other hand you could place it in the Update function the same style. Unity calls the Update function once every frame.

...
void Update(){
    if(currentScore < scoreToUpdate) {
        currentScore++;
        guiText.text = "Score: " + currentScore;
    }
}
...

However both of these methods do require that the class they are in inherits from monodevelop:

public class Scoring : MonoBehaviour 

Quick and dirty solution, using HOTween (which is free and open source). Note that it wont show all numbers, just as many as it can within transitionTime seconds.

using Holoville.HOTween;

...

int displayScore = 0;

public void updateScore (int newScore)
{

    if (oldScore != newScore) 
    {
        float transitionTime = .2f;
        HOTween.To(this, transitionTime, "displayScore", newScore);
    }

}

public void Update() {
    guiText.text = "" + displayScore
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM