Unity玩家本地得分排名系统的制作

UI的制作

首先,我们建一个新的场景把他命名为Scoring,在Scoring场景导入积分面板资源25.3(资源下载放在置顶了) 并设置渲染摄像机,在游戏结束时我们将切换到这个场景。

配置好将看到如下界面,资源来自bili up阿严Dev

其次,制作button按钮即返回主菜单功能,只需在Scoring UI ——Scoring Screen——Right Panel——Button Container内创建一个button就行了。

最后,将Scoring Screen里的Canvas取消掉。并将资源26.0里的New High Score Screen导入到Scoring UI下,并添加两个button,一个代表提交,一个代表取消。同理对New High Score Screen的Canvas属性进行取消。

我们将得到如下场景配置

如下效果,这里俺自由发挥了下。。。。

脚本的编写

对Scoring UI添加c#脚本书写以下代码,并一对一的将SerializeField导入。脚本主要功能,如果玩家破了纪录,仅展示New High Score Screen ——Canvas,玩家选择输入名字后点击提交后将取消New High Score Screen ——Canvas,激活Scoring Screen——Canvas的同时更新排行耪,如没有破纪录,直接激活Scoring Screen——Canvas。

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

public class ScoringUIController : MonoBehaviour
{
    [Header("== SCOREING SCREEN")]
    [SerializeField] Canvas scoringScreenCanvas;
    [SerializeField] Text playerScoreText;
    [SerializeField] Button buttonMainMenu;
    [SerializeField] Transform highScoreboardContainer;
    // Start is called before the first frame update

    [Header("== HIGH SCORE SCREEN==")]
    [SerializeField] Canvas newHighScoreScreenCanvas;
    [SerializeField] Button buttonCancel;
    [SerializeField] Button buttonSubmit;
    [SerializeField] InputField playerNameInputField;
    void Start()
    {
        Cursor.visible = true;//显示鼠标光标
        Cursor.lockState = CursorLockMode.None;
        if (ScoreManager.Instance.HasNewHighScore)
        {
            ShowNewHighScoreScreen();
        }
        else
        {
            ShowScreenCanvas();
        }
        
        buttonMainMenu.onClick.AddListener(OnButtonMainMenuCliked);
        buttonSubmit.onClick.AddListener(OnbuttonSubmitClicked);
        buttonCancel.onClick.AddListener(HideNewHighScoreScreen);
    }

    private void ShowNewHighScoreScreen()
    {
        newHighScoreScreenCanvas.enabled = true;
        buttonCancel.Select();
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    private void ShowScreenCanvas()
    {
        scoringScreenCanvas.enabled = true;
        //显示玩家得分,如果没有个属性自己想办法添加,这里本文是float属性的
        playerScoreText.text = DeliverManager.Instance.GetPointSum().ToString();
        buttonMainMenu.Select();
        //更新高分排行榜
        UpdateHighScoreLeaderboard();
        
    }
    //返回主菜单函数,点击设置Scoring的Canvas为空并返回主菜单没有主菜单自己做一个空白的也行,或许没有这个功能也行自己想办法
    private void OnButtonMainMenuCliked()
    {
        scoringScreenCanvas.enabled = false;
        //单纯的切换场景的封装,没有的话我放在备注代买里了
        Loader.Load(Loader.Scene.MainMenuScene);
    }

    private void HideNewHighScoreScreen()
    {
        newHighScoreScreenCanvas.enabled = false;
        ScoreManager.Instance.SavePlayerScoreData();
        ShowScreenCanvas();
    }
//更新排行榜
    private void UpdateHighScoreLeaderboard()
    {
        var playerScoredList =  ScoreManager.Instance.LoadPlayerScoreData().list;

        for (int i = 0;i< highScoreboardContainer.childCount;i++)
        {
            var child =  highScoreboardContainer.GetChild(i);
            child.Find("Rank").GetComponent<Text>().text = (i+1).ToString();
            child.Find("Score").GetComponent<Text>().text = playerScoredList[i].score.ToString();
            child.Find("Name").GetComponent<Text>().text = playerScoredList[i].playerName;
        }
    }

    private void OnbuttonSubmitClicked()
    {
        if (!string.IsNullOrEmpty(playerNameInputField.text))
        {
            ScoreManager.Instance.SetPlayerName(playerNameInputField.text);

        }

        HideNewHighScoreScreen();

    }

}

分数的存取JSON格式、排序

首先,作为读取文件我们先编写一个SaveSystem类代码如下:

using System.IO;
using UnityEngine;
//删除文件,保存文件,读取文件
public static class SaveSystem
{
    public static void Save(string saveFileName, object data)
    {
        var json = JsonUtility.ToJson(data);
        var path = Path.Combine(Application.persistentDataPath, saveFileName);

        try
        {
            File.WriteAllText(path, json);

            #if UNITY_EDITOR
            Debug.Log($"Successfully saved data to {path}.");
            #endif
        }
        catch (System.Exception exception)
        {
            #if UNITY_EDITOR
            Debug.LogError($"Failed to saved data to {path}. \n{exception}");
            #endif
        }
    }

    public static T Load<T>(string saveFileName)
    {
        var path = Path.Combine(Application.persistentDataPath, saveFileName);

        try
        {
            var json = File.ReadAllText(path);
            var data = JsonUtility.FromJson<T>(json);

            return data;
        }
        catch (System.Exception exception)
        {
            #if UNITY_EDITOR
            Debug.LogError($"Failed to load data from {path}. \n{exception}");
            #endif

            return default;
        }
    }

    public static void DeleteSaveFile(string saveFileName)
    {
        var path = Path.Combine(Application.persistentDataPath, saveFileName);

        try
        {
            File.Delete(path);
        }
        catch (System.Exception exception)
        {
            #if UNITY_EDITOR
            Debug.LogError($"Failed to delete {path}. \n{exception}");
            #endif
        }
    }

    public static bool SaveFileExists(string saveFileName)
    {
        var path = Path.Combine(Application.persistentDataPath, saveFileName);

        return File.Exists(path);
    }
}

然后对于分数管理我们创建ScoreManager脚本,这个脚本是可持续单例模式,编写脚本如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
public class ScoreManager : PersistentSingleton<ScoreManager>
{
    [System.Serializable] 
    public class PlayerScore
    {
        public float score;

        public string playerName;

        public PlayerScore(float score, string name)
        {
            this.score = score;
            this.playerName = name;
        }
    }

    [System.Serializable]
    public class PlayerScoreData
    {
        public
        List<PlayerScore> list = new List<PlayerScore>();
    }

    readonly string SaveFileName = "player_score.json";
    private  string playerName = "No Name";
    //玩家得分是否创了记录,我这得分是 DeliverManager.Instance.GetPointSum()这儿对应要修改
    public bool HasNewHighScore => DeliverManager.Instance.GetPointSum() > LoadPlayerScoreData().list[9].score;
    /*public bool HasNewHighScore(float score)
    {
        return score > LoadPlayerScoreData().list[9].score;
    }*/

    public void SetPlayerName(string newName)
    {
        playerName = newName;
    }
    public PlayerScoreData LoadPlayerScoreData()
    {
        PlayerScoreData playerScoreData = new PlayerScoreData();
       
        if (SaveSystem.SaveFileExists(SaveFileName))
        {
            playerScoreData = SaveSystem.Load<PlayerScoreData>(SaveFileName);
        }
        else
        {
            while(playerScoreData.list.Count < 10)
            {
                playerScoreData.list.Add(new PlayerScore(0, playerName));
            }

            SaveSystem.Save(SaveFileName, playerScoreData);
        }

        return playerScoreData;
    }

    public void SavePlayerScoreData()
    {
        PlayerScoreData playerScoreData = LoadPlayerScoreData();
        //填入游戏总分数和玩家名字,名字默认NoName,如玩家有输入则修改
        playerScoreData.list.Add(new PlayerScore(DeliverManager.Instance.GetPointSum(), playerName));
        //这里排序算法可以尝试其他,如冒泡排序
        playerScoreData.list.Sort((x, y) => y.score.CompareTo(x.score));

        SaveSystem.Save(SaveFileName, playerScoreData);

    }
    
}

备注脚本

只想运行Loader类(切换场景)的实现如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public static class Loader 
{
    //单纯切换场景枚举
    public enum Scene
    {
        MainMenuScene,
        GameScene,
        LoadingScene,
        Scoring

    }
    private static Scene targetScene;

    public static void Load(Scene targetScene)
    {

        Loader.targetScene = targetScene;

        SceneManager.LoadScene(Scene.LoadingScene.ToString());

        
    }

    public static void LoaderCallback()
    {
        SceneManager.LoadScene(targetScene.ToString());
    }
}

可持续单例类如下

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

public class PersistentSingleton<T> : MonoBehaviour where T : Component
{
    public static T Instance { get; private set; }

    protected virtual void Awake()
    {
        if (Instance == null)
        {
            Instance = this as T;
        }
        //如果场景中已经存在一个一样的持久单例了 就删掉这一个
        else if (Instance != this)
        {
            Destroy(gameObject);
        }
        DontDestroyOnLoad(gameObject);
    }
}

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值