简体   繁体   English

Unity 在重播时将分数重置为 0

[英]Unity reset score to 0 on replay

Salutations.问候。 I have a working script that carries my game score over from level to level.我有一个工作脚本,可以将我的游戏分数从一个级别传递到另一个级别。 The issue is that my replay level script does not reset to 0 but preserves the score from prior to reset.问题是我的重播级别脚本没有重置为 0,而是保留了重置之前的分数。 Suggestions on how to get the replay script to reset score to 0 without interfering with score carryover script would be greatly appreciated关于如何在不干扰分数结转脚本的情况下让重播脚本将分数重置为 0 的建议将不胜感激

Score Carryover Script分数结转脚本

{
  
public static int scoreValue = 0;
Text score;

void Start()
{
    score = GetComponent<Text>();
    scoreValue = PlayerPrefs.GetInt("Player Score");
}

void Update()
{
    score.text = " " + scoreValue;
    PlayerPrefs.SetInt("Player Score", scoreValue);
}

} }

Replay Level Script重播关卡脚本

{ {

public static int scoreValue = 0;
Text score;

public void RestartLevel()
{
    SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    score = GetComponent<Text>();
    score.text = " " + 0;
    
}


public void Awake()
{
    Time.timeScale = 1;
    
}

Alright sorry just got home.好吧抱歉刚到家。 There are a few issues that have been addressed in the comments.评论中已经解决了一些问题。 One issue that I am seeing is the constant use of PlayerPrefs.SetInt("Player Score", scoreValue);我看到的一个问题是不断使用PlayerPrefs.SetInt("Player Score", scoreValue); in an Update() function.Update() function 中。 Unless absolutely needed, I refrain from using any sort of Update() method as some of the methods called can computationally get rather heavy.除非绝对需要,否则我不会使用任何类型的Update()方法,因为某些调用的方法在计算上会变得相当繁重。 With a smaller project, it is negligible, but after months of working on a project, something like this can bottleneck your project.对于一个较小的项目,它可以忽略不计,但经过几个月的项目工作,这样的事情可能会成为您项目的瓶颈。

Aside from the nitpicky reason of not having this method in Update() , it very well could be the reason why the data is not resetting as it is setting it every frame.除了在Update()中没有这个方法的挑剔原因之外,这很可能是数据没有重置的原因,因为它每帧都设置它。 I did a little bit of rewriting to help you out a bit.我做了一些重写来帮助你。 I am going to employ the Singleton Pattern which some believe is bad, but I disagree.我将使用Singleton 模式,有些人认为这是不好的,但我不同意。 I find them very useful when used in proper situations and when they are not overused.我发现它们在适当的情况下使用并且没有过度使用时非常有用。 To briefly and generally explain the Singleton Pattern, it is effectively a static instance of a class that is global so all other scripts can access it by accessing its instance.为了简要和一般地解释 Singleton 模式,它实际上是 class 的 static 实例,它是全局的,因此所有其他脚本都可以通过访问其实例来访问它。 Think of it as a class that exists once and every other script can use it.将其视为存在一次的 class,其他所有脚本都可以使用它。

Firstly, create a new script called Singleton.cs and copy the code below.首先,创建一个名为Singleton.cs的新脚本并复制以下代码。 I stripped down the Unity implementation and commented it to be a little less confusing.我剥离了 Unity 的实现,并评论说它不那么令人困惑。

// from the Unity wiki
// http://wiki.unity3d.com/index.php/Singleton
// base class of a singelton pattern 
using UnityEngine;

/// <summary>
/// Inherit from this base class to create a singleton.
/// e.g. public class MyClassName : Singleton<MyClassName> {}
/// </summary>
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    // Check to see if we're about to be destroyed.
    private static object m_Lock = new object();
    private static T m_Instance;

    /// <summary>
    /// Determines if this instance exists
    /// </summary>
    /// <returns></returns>
    public static bool HasInstance() { return m_Instance != null; }

    /// <summary>
    /// Access singleton instance through this propriety.
    /// </summary>
    public static T Instance
    {
        get
        {
            lock (m_Lock)
            {
                if (m_Instance == null)
                {
                    // Search for existing instance.
                    m_Instance = (T)FindObjectOfType(typeof(T));

                    // Create new instance if one doesn't already exist.
                    if (m_Instance == null)
                    {
                        // Need to create a new GameObject to attach the singleton to.
                        var singletonObject = new GameObject();
                        m_Instance = singletonObject.AddComponent<T>();
                        singletonObject.name = typeof(T).ToString() + " (Singleton)";

                        // Make instance persistent.
                        DontDestroyOnLoad(singletonObject);
                    }
                }

                return m_Instance;
            }
        }
    }
}

Now for the score carry over script .现在为分数carry over script I changed it a bit to be a score manager.我改变了一点,成为一名得分经理。 What this means is up to you, but the general idea of a manager is that it holds all data relating to whatever it is managing.这意味着什么取决于您,但管理器的一般概念是它保存与其管理的任何内容相关的所有数据。 In your case, it will manage, save, manipulate and display the score.在您的情况下,它将管理、保存、操作和显示分数。 Other scripts that need to access the score, change the score, etc. call it.其他需要访问分数、更改分数等的脚本调用它。

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

/// <summary>
/// Scoremanager that handles all score related functionality
/// </summary>
public class ScoreManager : Singleton<ScoreManager>
{
    [SerializeField] private Text score;
    private int scoreValue = 0;

    private void OnEnable()
    {
        SceneManager.sceneLoaded += NewSceneLoaded;
    }

    private void OnDisable()
    {
        SceneManager.sceneLoaded -= NewSceneLoaded;
    }

    /// <summary>
    /// Listen for when a new scene is loaded - set our score to the current player value
    /// </summary>
    /// <param name="scene"></param>
    /// <param name="mode"></param>
    public void NewSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        // again just reusing the same function for less code rewriting
        AddScore(PlayerPrefs.GetInt("Player Score"));
    }

    /// <summary>
    /// Adds any given amount to our score, saves it and displays it to the user
    /// </summary>
    /// <param name="amount"></param>
    public void AddScore(int amount)
    {
        scoreValue += amount;
        UpdateScoreUI();
        PlayerPrefs.SetInt("Player Score", scoreValue);
    }

    public void ResetScore()
    {
        // nice trick to reset the score to 0 by negating the entire score
        // re-uses all of the other code as well to update UI and save the score to Player Prefs
        AddScore(-scoreValue);
    }

    /// <summary>
    /// Updates the UI of our score
    /// </summary>
    private void UpdateScoreUI()
    {
        score.text = "Score: " + scoreValue;
    }
}

As you can see, it is inheriting from the Singleton class meaning it can be called from anywhere in the project as long as the object exists in the scene.如您所见,它继承自Singleton class,这意味着只要场景中存在 object,就可以从项目中的任何位置调用它。 Make sure to place a ScoreManager in every scene.确保在每个场景中都放置一个ScoreManager The other change is that I made the Text object a private field and Serialized it in the inspector.另一个更改是我将Text object 设为私有字段并在检查器中对其进行Serialized This just means other classes can not access it, but Unity will show it in the inspector so you can drag in your Text object into the script to get the reference set.这只是意味着其他类无法访问它,但 Unity 会在检查器中显示它,因此您可以将Text object 拖到脚本中以获取参考集。 One other note I will make is I am subscribing to the SceneManager delegate event of sceneLoaded which is called when the scene finishes loading.我要说明的另一点是我订阅了sceneLoaded的 SceneManager 委托事件,该事件在场景完成加载时被调用。 I am using it to initially set the UI and initialize your score properly.我正在使用它来初始设置 UI 并正确初始化您的分数。

Next is an example script that calls the ScoreManager to increase the score.接下来是一个示例脚本,它调用ScoreManager来增加分数。 It has an int that increases the score by some value I set in the inspector.它有一个 int 值,可以将分数增加我在检查器中设置的某个值。 You can attach this to any of the objects that change the score or, you can copy the one line that matters.您可以将其附加到任何更改分数的对象上,或者您可以复制重要的一行。

using UnityEngine;使用 UnityEngine;

/// <summary>
/// Example object that increases our score
/// </summary>
public class IncreaseScore : MonoBehaviour
{
    // the amount of score that this object gives when its IncScore is called
    [SerializeField] private int PointsWorth = 0;

    /// <summary>
    /// Increaes our score after some event - this example I am using a button to increase it
    /// whenever you click an enemy or object, etc. use the same function
    /// </summary>
    public void IncScore()
    {
        ScoreManager.Instance.AddScore(PointsWorth);
    }
}

Just to reiterate, the one line that changes the current score is this one: ScoreManager.Instance.AddScore(PointsWorth);重申一下,改变当前分数的一行是这一行: ScoreManager.Instance.AddScore(PointsWorth); . . Change PointsWorth to whatever value you would like to change it by.PointsWorth更改为您想要更改的任何值。

Finally, I revised your ReplayLevel a bit to assure that the score is reset to 0 when the ResetLevel function is called.最后,我稍微修改了您的ReplayLevel以确保在调用ResetLevel function 时将分数重置为 0。

using UnityEngine;
using UnityEngine.SceneManagement;

public class ReplayLevel : MonoBehaviour
{
    public void Awake()
    {
        Time.timeScale = 1;
    }

    public void RestartLevel()
    {
        // reset our score as we are resetting the level
        PlayerPrefs.SetInt("Player Score", 0);
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    public void NewLevel()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }
}

Let me know if you have questions as this was quite a lot.如果您有任何问题,请告诉我,因为这非常多。 I tested this myself as it was more involved and I have it locally working in a scene with a bunch of buttons just calling the functions.我自己对此进行了测试,因为它涉及更多,并且我让它在一个场景中本地工作,其中有一堆按钮只是调用函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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