文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Unity如何制作一个分数统计系统

2023-06-21 22:50

关注

这篇文章将为大家详细讲解有关Unity如何制作一个分数统计系统,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

首先定义一个分数信息的数据结构,使用Serializable特性使其可序列化:

using System;using UnityEngine; namespace SK.Framework{    /// <summary>    /// 分数信息    /// </summary>    [Serializable]    public class ScoreInfo    {        /// <summary>        /// ID        /// </summary>        public int id;        /// <summary>        /// 描述        /// </summary>        [TextArea]        public string description;        /// <summary>        /// 分值        /// </summary>        public float value;    }}

ScoreInfo类可序列化后,创建ScoreProfile类继承ScriptableObject使其作为可通过菜单创建的Asset资产:

using UnityEngine; namespace SK.Framework{    /// <summary>    /// 分数配置文件    /// </summary>    [CreateAssetMenu]    public class ScoreProfile : ScriptableObject    {        public ScoreInfo[] scores = new ScoreInfo[0];    }}

Unity如何制作一个分数统计系统

使用ScoreIDConstant类编写所有分数项ID常量,创建ScoreID特性并使用PropertyDrawer使其可在面板选择:

namespace SK.Framework{    public sealed class ScoreIDConstant    {        public const int INVALID = -1;    }}
using UnityEngine; #if UNITY_EDITORusing UnityEditor;using System;using System.Reflection;using System.Collections;#endif namespace SK.Framework{    public class ScoreIDAttribute : PropertyAttribute { } #if UNITY_EDITOR    [CustomPropertyDrawer(typeof(ScoreIDAttribute))]    public class ScoreIDPropertyAttributeDrawer : PropertyDrawer    {        private int[] scoreIDArray;        private GUIContent[] scoreIDConstArray;         public override float GetPropertyHeight(SerializedProperty property, GUIContent label)        {            return base.GetPropertyHeight(property, label);        }         public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)        {            if (scoreIDConstArray == null)            {                ArrayList constants = new ArrayList();                FieldInfo[] fieldInfos = typeof(ScoreIDConstant).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);                for (int i = 0; i < fieldInfos.Length; i++)                {                    var fi = fieldInfos[i];                    if (fi.IsLiteral && !fi.IsInitOnly) constants.Add(fi);                }                FieldInfo[] fieldInfoArray = (FieldInfo[])constants.ToArray(typeof(FieldInfo));                scoreIDArray = new int[fieldInfoArray.Length];                scoreIDConstArray = new GUIContent[fieldInfoArray.Length];                for (int i = 0; i < fieldInfoArray.Length; i++)                {                    scoreIDConstArray[i] = new GUIContent(fieldInfoArray[i].Name);                    scoreIDArray[i] = (int)fieldInfoArray[i].GetValue(null);                }            }            var index = Array.IndexOf(scoreIDArray, property.intValue);            index = Mathf.Clamp(index, 0, scoreIDArray.Length);            index = EditorGUI.Popup(position, label, index, scoreIDConstArray);            property.intValue = scoreIDArray[index];        }    }#endif}

有了ScoreID特性后,用于ScoreInfo中的id字段:

using System;using UnityEngine; namespace SK.Framework{    /// <summary>    /// 分数信息    /// </summary>    [Serializable]    public class ScoreInfo    {        /// <summary>        /// ID        /// </summary>        [ScoreID]        public int id;        /// <summary>        /// 描述        /// </summary>        [TextArea]        public string description;        /// <summary>        /// 分值        /// </summary>        public float value;    }}

Unity如何制作一个分数统计系统

数据可配置后,创建分数项Score类,声明以下字段:Flag表示该分数项的标识,注册分数项时返回该标识,用于后续获取或取消该分数项分值;Description即分数项的描述;Value表示该分数项的分值;IsObtained用于标记该分数项的分值是否已经获得。

namespace SK.Framework{    /// <summary>    /// 分数项    /// </summary>    public class Score    {        /// <summary>        /// 标识        /// </summary>        public string Flag { get; private set; }        /// <summary>        /// 描述        /// </summary>        public string Description { get; private set; }        /// <summary>        /// 分值        /// </summary>        public float Value { get; private set; }        /// <summary>        /// 是否已经获得分值        /// </summary>        public bool IsObtained { get; set; }         public Score(string flag, string description, float value)        {            Flag = flag;            Description = description;            Value = value;        }    }}

为了实现一个分数组合,例如某项操作,通过A操作方式可获得5分,通过B操作方式可获得3分,它们之间是互斥的,即获得了前者的5分,就不会获得后者的3分,创建ScoreGroup类:

using System.Collections.Generic; namespace SK.Framework{    /// <summary>    /// 分数组合    /// </summary>    public class ScoreGroup    {        /// <summary>        /// 组合描述        /// </summary>        public string Description { get; private set; }        /// <summary>        /// 计分模式        /// Additive表示组合内分值进行累加        /// MutuallyExclusive表示组内各分数项互斥 获得其中一项分值 则取消其它项分值        /// </summary>        public ValueMode ValueMode { get; private set; }         public List<Score> Scores { get; private set; }         public ScoreGroup(string description, ValueMode valueMode, params Score[] scores)        {            Description = description;            ValueMode = valueMode;            Scores = new List<Score>(scores);        }         public bool Obtain(string flag)        {            var target = Scores.Find(m => m.Flag == flag);            if (target != null)            {                switch (ValueMode)                {                    case ValueMode.Additive: target.IsObtained = true; break;                    case ValueMode.MutuallyExclusive:                        for (int i = 0; i < Scores.Count; i++)                        {                            Scores[i].IsObtained = Scores[i] == target;                        }                        break;                    default: break;                }                if (ScoreMaster.DebugMode)                {                    ScoreMaster.LogInfo($"获取分数组合 [{Description}] 中标识为 [{flag}] 的分值 [{target.Description}]");                }                return true;            }            if (ScoreMaster.DebugMode)            {                ScoreMaster.LogError($"分数组合 [{Description}] 中不存在标识为 [{flag}] 的分数项.");            }            return false;        }        public bool Cancle(string flag)        {            var target = Scores.Find(m => m.Flag == flag);            if (target != null)            {                if (ScoreMaster.DebugMode)                {                    ScoreMaster.LogInfo($"取消分数组合 [{Description}] 中标识为 [{flag}] 的分数项分值 [{target.Description}]");                }                target.IsObtained = false;                return true;            }            if (ScoreMaster.DebugMode)            {                ScoreMaster.LogError($"分数组合 [{Description}] 中不存在标识为 [{flag}] 的分数项.");            }            return false;        }    }}
namespace SK.Framework{    /// <summary>    /// 计分方式    /// </summary>    public enum ValueMode    {        /// <summary>        /// 累加的        /// </summary>        Additive,        /// <summary>        /// 互斥的        /// </summary>        MutuallyExclusive,    }}

最终编写分数管理类,封装Create、Obtain、Cancle、GetSum函数,分别用于创建分数组合、获取分数、取消分数、获取总分,实现Editor类使分数信息在Inspector面板可视化:

using System;using UnityEngine;using System.Collections.Generic; #if UNITY_EDITORusing UnityEditor;using System.Reflection;#endif namespace SK.Framework{    public class ScoreMaster : MonoBehaviour    {        #region NonPublic Variables        private static ScoreMaster instance;        [SerializeField] private ScoreProfile profile;        private readonly Dictionary<string, ScoreGroup> groups = new Dictionary<string, ScoreGroup>();        #endregion         #region Public Properties        public static ScoreMaster Instance        {            get            {                if (instance == null)                {                    instance = FindObjectOfType<ScoreMaster>();                }                if (instance == null)                {                    instance = new GameObject("[SKFramework.Score]").AddComponent<ScoreMaster>();                    instance.profile = Resources.Load<ScoreProfile>("Score Profile");                    if (instance.profile == null && DebugMode)                    {                        LogError("加载分数信息配置表失败.");                    }                }                return instance;            }        }        #endregion         #region NonPublic Methods        private string[] CreateScore(string description, ValueMode valueMode, params int[] idArray)        {            Score[] scores = new Score[idArray.Length];            string[] flags = new string[idArray.Length];            for (int i = 0; i < idArray.Length; i++)            {                var info = Array.Find(profile.scores, m => m.id == idArray[i]);                if (info != null)                {                    var flag = Guid.NewGuid().ToString();                    flags[i] = flag;                    scores[i] = new Score(flag, info.description, info.value);                    if (DebugMode) LogInfo($"创建分数ID为 [{idArray[i]}] 的分数项 [{info.description}] flag: {flag}");                }                else if (DebugMode)                {                    LogError($"配置中不存在ID为 [{idArray[i]}] 的分数信息.");                }            }            ScoreGroup group = new ScoreGroup(description, valueMode, scores);            groups.Add(description, group);            if (DebugMode)            {                LogInfo($"创建分数组合 [{description}] 计分模式[{valueMode}]");            }            return flags;        }        private bool ObtainValue(string groupDescription, string flag)        {            if (groups.TryGetValue(groupDescription, out ScoreGroup target))            {                return target.Obtain(flag);            }            if (DebugMode)            {                LogError($"不存在分数组合 [{groupDescription}].");            }            return false;        }        private bool CancleValue(string groupDescription, string flag)        {            if (groups.TryGetValue(groupDescription, out ScoreGroup target))            {                return target.Cancle(flag);            }            if (DebugMode)            {                LogError($"不存在分数组合 [{groupDescription}].");            }            return false;        }        private float GetSumValue()        {            float retV = 0f;            foreach (var kv in groups)            {                var scores = kv.Value.Scores;                for (int i = 0; i < scores.Count; i++)                {                    var score = scores[i];                    if (score.IsObtained)                    {                        retV += score.Value;                    }                }            }            return retV;        }        #endregion         #region Public Methods        /// <summary>        /// 创建分数组合        /// </summary>        /// <param name="description">分数组合描述</param>        /// <param name="valueMode">分数组计分方式</param>        /// <param name="idArray">分数信息ID组合</param>        /// <returns>返回分数项标识符组合</returns>        public static string[] Create(string description, ValueMode valueMode, params int[] idArray)        {            return Instance.CreateScore(description, valueMode, idArray);        }        /// <summary>        /// 获取分数组合中指定标识分数项的分值        /// </summary>        /// <param name="groupDescription">分数组合</param>        /// <param name="flag">分数项标识</param>        /// <returns>获取成功返回true 否则返回false</returns>        public static bool Obtain(string groupDescription, string flag)        {            return Instance.ObtainValue(groupDescription, flag);        }        /// <summary>        /// 取消分数组合中指定标识分数项的分值        /// </summary>        /// <param name="groupDescription">分数组合</param>        /// <param name="flag">分数项标识</param>        /// <returns></returns>        public static bool Cancle(string groupDescription, string flag)        {            return Instance.CancleValue(groupDescription, flag);        }        /// <summary>        /// 获取总分值        /// </summary>        /// <returns>总分值</returns>        public static float GetSum()        {            return Instance.GetSumValue();        }        #endregion         #region Debugger        public static bool DebugMode = true;         public static void LogInfo(string info)        {            Debug.Log($"<color=cyan><b>[SKFramework.Score.Info]</b></color> --> {info}");        }        public static void LogWarn(string warn)        {            Debug.Log($"<color=yellow><b>[SKFramework.Score.Warn]</b></color> --> {warn}");        }        public static void LogError(string error)        {            Debug.Log($"<color=red><b>[SKFramework.Score.Error]</b></color> --> {error}");        }        #endregion    } #if UNITY_EDITOR    [CustomEditor(typeof(ScoreMaster))]    public class ScoreMasterInspector : Editor    {        private SerializedProperty profile;        private Dictionary<string, ScoreGroup> groups;        private Dictionary<ScoreGroup, bool> groupFoldout;         private void OnEnable()        {            profile = serializedObject.FindProperty("profile");        }         public override void OnInspectorGUI()        {            EditorGUILayout.PropertyField(profile);            if (GUI.changed)            {                serializedObject.ApplyModifiedProperties();                EditorUtility.SetDirty(target);            }             if (!Application.isPlaying) return;            Color color = GUI.color;            GUI.color = Color.cyan;            OnRuntimeGUI();            GUI.color = color;        }        private void OnRuntimeGUI()        {            if (groupFoldout == null)            {                groups = typeof(ScoreMaster).GetField("groups", BindingFlags.Instance | BindingFlags.NonPublic)                    .GetValue(ScoreMaster.Instance) as Dictionary<string, ScoreGroup>;                groupFoldout = new Dictionary<ScoreGroup, bool>();            }             foreach (var kv in groups)            {                if (!groupFoldout.ContainsKey(kv.Value))                {                    groupFoldout.Add(kv.Value, false);                }                 ScoreGroup group = kv.Value;                groupFoldout[group] = EditorGUILayout.Foldout(groupFoldout[group], group.Description);                if (groupFoldout[group])                {                    GUILayout.Label($"计分模式: {(group.ValueMode == ValueMode.Additive ? "累加" : "互斥")}");                    for (int i = 0; i < group.Scores.Count; i++)                    {                        Score score = group.Scores[i];                        GUILayout.BeginVertical("Box");                        GUI.color = score.IsObtained ? Color.green : Color.cyan;                        GUILayout.Label($"描述: {score.Description}");                        GUILayout.Label($"标识: {score.Flag}");                        GUILayout.BeginHorizontal();                        GUILayout.Label($"分值: {score.Value}   {(score.IsObtained ? "√" : "")}");                        GUI.color = Color.cyan;                        GUILayout.FlexibleSpace();                        GUI.color = Color.yellow;                        if (GUILayout.Button("Obtain", "ButtonLeft", GUILayout.Width(50f)))                        {                            ScoreMaster.Obtain(group.Description, score.Flag);                        }                        if (GUILayout.Button("Cancle", "ButtonRight", GUILayout.Width(50f)))                        {                            ScoreMaster.Cancle(group.Description, score.Flag);                        }                        GUI.color = Color.cyan;                        GUILayout.EndHorizontal();                        GUILayout.EndVertical();                    }                }            }            GUILayout.BeginHorizontal();            GUILayout.FlexibleSpace();            GUILayout.Label($"总分: {ScoreMaster.GetSum()}", "LargeLabel");            GUILayout.Space(50f);            GUILayout.EndHorizontal();        }    }#endif}

测试:

namespace SK.Framework{    public sealed class ScoreIDConstant    {        public const int INVALID = -1;         public const int TEST_A = 0;        public const int TEST_B = 1;        public const int TEST_C = 2;        public const int TEST_D = 3;    }}

Unity如何制作一个分数统计系统

using UnityEngine;using SK.Framework; public class Foo : MonoBehaviour{    private string[] flags;     private void Start()    {        flags = ScoreMaster.Create("测试", ValueMode.MutuallyExclusive,            ScoreIDConstant.TEST_A, ScoreIDConstant.TEST_B,             ScoreIDConstant.TEST_C, ScoreIDConstant.TEST_D);    }     private void OnGUI()    {        if (GUILayout.Button("A", GUILayout.Width(200f), GUILayout.Height(50f)))        {            ScoreMaster.Obtain("测试", flags[0]);        }        if (GUILayout.Button("B", GUILayout.Width(200f), GUILayout.Height(50f)))        {            ScoreMaster.Obtain("测试", flags[1]);        }        if (GUILayout.Button("C", GUILayout.Width(200f), GUILayout.Height(50f)))        {            ScoreMaster.Obtain("测试", flags[2]);        }        if (GUILayout.Button("D", GUILayout.Width(200f), GUILayout.Height(50f)))        {            ScoreMaster.Obtain("测试", flags[3]);        }        GUILayout.Label($"总分: {ScoreMaster.GetSum()}");    }}

Unity如何制作一个分数统计系统

Unity如何制作一个分数统计系统 

关于“Unity如何制作一个分数统计系统”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯