游戏开始时得分并非以0开头

时间:2019-08-22 11:51:13

标签: unity3d

我正在做一个游戏,我试图在场景之间传递数据(分数)。问题在于当我再次统一比赛时,得分保持4-5,10分取决于最后一个环节,并且从第一个场景开始时不能从0开始正常。 (我仍然希望在场景之间保存数据,但是当我单击“统一运行”时要重置分数) 我有2个脚本,应该更改什么?

得分

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Score : MonoBehaviour
{
    public Text scoreText;
    public int score;
    public Button button;

    // Use this for initialization
    void Start()
    {
        score = PlayerPrefs.GetInt("score", 0);
        GameObject.DontDestroyOnLoad(this.gameObject);
        Debug.LogFormat("Current Score: {0}", score);
        Button btn = GetComponent<Button>();
        button.onClick.AddListener(TaskOnClick);
    }

    void Update()
    {
        scoreText.text = "Score: " + score;
    }

    void OnDestroy()
    {
        PlayerPrefs.SetInt("score", score);
    }

    public void AddScore(int s)
    {
        score += s;
    }

    public int GetScore()
    {
        return score;
    }

    void TaskOnClick()
    {
        score++;
    }
}

ScorePanelUpdater

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ScorePanelUpdater : MonoBehaviour
{
    void Update()
    {
        GameObject go = GameObject.Find("Score");
        if(go == null)
        {
            Debug.LogError("Failed");
            this.enabled = false;
            return;
        }

        Score gs = go.GetComponent<Score>();

        GetComponent<Text>().text = " Score: " + gs.GetScore();
    }
}

3 个答案:

答案 0 :(得分:2)

您正在使用DontDestroyOnLoad,因此您的实例和相应的值无论如何也将在每个场景中维护。 您完全不需要/根本不使用PlayerPrefs


要回答您的问题:您有

void OnDestroy()
{
    PlayerPrefs.SetInt("score", score);
}

因此,一旦此实例销毁,最后的值将始终存储..什么时候发生?由于您正在使用DontDestroyOnLoad,因此除非您关闭游戏,否则它不会发生从未发生,退出游戏模式=>由于

,最后一次存储该值并在下次游戏开始时恢复该值。
void Start()
{
    score = PlayerPrefs.GetInt("score", 0);
    ...
}

解决方案:在0OnDestroy)中将其重置为PlayerPrefs.SetInt("score", 0);,或者从脚本中完全删除PlayerPrefs!您不需要它。


this answer已经提到了更简单的方法:您可以简单地使用static字段。同样,由于您正在使用DontDestroyOnLoad,因此实际上并不需要这样做,因为它仍然可以在所有场景中使用。

但是您的代码中还有其他一些问题:

不要重复使用FindGetComponent,如果在Update中使用..更糟糕的是,这些效率很低!同样,对于Update的值实际上发生更改之后,只需要更改事件驱动的事情,就根本不需要使用score

由于效率方面还有很多其他问题,因此我会对此加以扩展,并且不会在MonoBehaviour内使用它,而在static class中将其完全分开,例如

public static class GameInformation
{
    private static int _score = 0;

    // have an event to register listeners
    public static event Action<int> OnScoreChanged;

    // public property
    public static int Score
    {
        get { return _score;}
        set 
        {
            _score = value;

            // invoke an event to inform all registered listeners
            OnScoreChanged?.Invoke(_score);
        }
    }
}

此类不需要实例,但可以在运行时从任何地方进行访问。

现在您可以在Score

public class Score : MonoBehaviour
{
    public Text scoreText;
    public Button button;

    // Use this for initialization
    void Start()
    {
        DontDestroyOnLoad(gameObject);

        if(!button) button = GetComponent<Button>();
        button.onClick.AddListener(() => { GameInformation.Score++; });

        GameInformation.OnScoreChanged -= OnScoreChanged;
        GameInformation.OnScoreChanged += OnScoreChanged;

        // invoke once now with current value
        Debug.LogFormat("Current Score: {0}", GameInformation.Score);
        OnScoreChanged(GameInformation.Score);

    }

    private void OnDestroy()
    {
        GameInformation.OnScoreChanged -= OnScoreChanged;
    }

    private void OnScoreChanged(int newValue)
    {
        scoreText.text = "Score: " + newValue;
    }


    // These two make not much sense .. since the value already was public
    // you wouldn't need methods for this
    // anyway now you could directly do it on GameInformation instead
    public void AddScore(int s)
    {
        GameInformation.Score += s;
    }

    public int GetScore()
    {
        return GameInformation.Score;
    }
}

并且在ScorePanelUpdater中也只需添加回调

public class ScorePanelUpdater : MonoBehaviour
{
    // better if you can already reference this via Inspector
    [SerializeField] Text text;

    void Awake()
    {
        if(!text) text = GetComponent<Text>();

        // it's always save to remove listeners before adding them
        // makes sure it is added only once
        GameInformation.OnScoreChanged -= OnScoreChanged;
        GameInformation.OnScoreChanged += OnScoreChanged;

        // invoke once now with current value
        OnScoreChanged(GameInformation.Score);
    }

    private void OnDestroy()
    {
        GameInformation.OnScoreChanged -= OnScoreChanged;
    }

    private void OnScoreChanged(int newValue)
    {
        text.text = "Score: " + newValue;
    }
}

答案 1 :(得分:1)

您可以做的另一件事是将得分保存为静态变量。这样,您可以从每个场景访问它,但是一旦重新启动游戏,该值将被重置。

public static int score = 0;

答案 2 :(得分:0)

尝试将以下内容添加到"2019-08-15T15:58:14.597Z"(第一个场景)或<template> <v-content class="mt-12 ml-12"> <h1 class="font-weight-black display-3">Servers</h1> <v-data-table class="elevation-1" :headers="headers" :items="columns" :items-per-page="15" > </v-data-table> <ul id="example-1"> <li v-for="(data, index) in columns.data" :key="index"> {{ data.attributes }} </li> </ul> </v-content> </template> <script> import instances from '../services/instances'; export default { data() { return { columns: [], headers: [ { text: 'Server Name', value: 'attributes.name' }, { text: 'Spieler', value: 'attributes.playerCount' }, { text: 'Avg. FPS', value: 'attributes.details.rust_fps_avg' }, { text: 'Wiped', value: 'attributes.details.rust_last_wipe' }, ], }; }, async created() { const { data } = await instances.createInstance(); this.columns = data.data; this.columns.forEach((entry) => { const { players, maxPlayers } = entry.attributes; entry.attributes.playerCount = `${players} / ${maxPlayers}`; const { rust_last_wipe } = entry.attributes.details; const mmmm = new Date(entry.attributes.details.rust_last_wipe); entry.attributes.details.rust_last_wipe = `${mmmm.getDate()}.${mmmm.getMonth() + 1}.${mmmm.getFullYear()}`; }); console.log(this.columns); }, }; </script> (最后一个场景):

Start()

对于OnApplicationQuit()

PlayerPrefs.SetInt("score", 0);