Unity 在重播时将分数重置为 0 [英] Unity reset score to 0 on replay

查看:38
本文介绍了Unity 在重播时将分数重置为 0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

致敬!我有一个工作脚本,可以将我的游戏分数从一个级别传递到另一个级别.问题是我的重播级别脚本没有重置为 0,而是保留了重置之前的分数.关于如何让重播脚本将分数重置为 0 而不干扰分数结转脚本的建议将不胜感激

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. Suggestions on how to get the replay script to reset score to 0 without interfering with score carryover script would be greatly appreciated

分数结转脚本

{
  
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);
}

}

重放关卡脚本

{

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;
    
}

推荐答案

好的,抱歉刚到家.评论中有几个问题已经解决.我看到的一个问题是在 Update() 函数中不断使用 PlayerPrefs.SetInt("Player Score", scoreValue);.除非绝对需要,否则我不会使用任何类型的 Update() 方法,因为调用的某些方法在计算上会变得相当繁重.对于较小的项目,它可以忽略不计,但经过数月的项目工作后,这样的事情可能会阻碍您的项目.

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); in an 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. With a smaller project, it is negligible, but after months of working on a project, something like this can bottleneck your project.

除了在 Update() 中没有这个方法的挑剔原因之外,这很可能是数据没有重置的原因,因为它每帧都设置它.我做了一些重写来帮助你.我将采用 Singleton Pattern 有些人认为这是不好的,但我不同意.我发现它们在适当的情况下使用时非常有用,并且不会被过度使用.简单而概括地解释单例模式,它实际上是一个全局类的静态实例,因此所有其他脚本都可以通过访问它的实例来访问它.把它想象成一个存在一次的类,其他所有脚本都可以使用它.

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. 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. 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. Think of it as a class that exists once and every other script can use it.

首先,创建一个名为 Singleton.cs 的新脚本并复制下面的代码.我剥离了 Unity 实现并评论说它不那么令人困惑.

Firstly, create a new script called Singleton.cs and copy the code below. I stripped down the Unity implementation and commented it to be a little less confusing.

// 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. 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;
    }
}

如您所见,它继承自 Singleton 类,这意味着只要对象存在于场景中,就可以从项目中的任何位置调用它.确保在每个场景中放置一个 ScoreManager.另一个变化是我在检查器中将 Text 对象设为私有字段并Serialized.这只是意味着其他类无法访问它,但 Unity 会在检查器中显示它,因此您可以将 Text 对象拖入脚本以获取引用集.我要做的另一件事是我订阅了 sceneLoaded 的 SceneManager 委托事件,该事件在场景加载完成时被调用.我正在使用它来初始设置 UI 并正确初始化您的分数.

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. Make sure to place a ScoreManager in every scene. The other change is that I made the Text object a private field and Serialized it in the inspector. 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. 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. I am using it to initially set the UI and initialize your score properly.

接下来是调用 ScoreManager 来增加分数的示例脚本.它有一个 int 值,可以通过我在检查器中设置的某个值来增加分数.您可以将其附加到任何更改分数的对象上,也可以复制重要的一行.

Next is an example script that calls the ScoreManager to increase the score. It has an int that increases the score by some value I set in the inspector. You can attach this to any of the objects that change the score or, you can copy the one line that matters.

使用 UnityEngine;

using 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);
    }
}

重申一下,改变当前分数的一行是:ScoreManager.Instance.AddScore(PointsWorth);.将 PointsWorth 更改为您想要更改的任何值.

Just to reiterate, the one line that changes the current score is this one: ScoreManager.Instance.AddScore(PointsWorth);. Change PointsWorth to whatever value you would like to change it by.

最后,我修改了您的 ReplayLevel 以确保在调用 ResetLevel 函数时分数重置为 0.

Finally, I revised your ReplayLevel a bit to assure that the score is reset to 0 when the ResetLevel function is called.

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.

这篇关于Unity 在重播时将分数重置为 0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆