In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article will explain in detail how to make a score statistics system for Unity. The editor thinks it is very practical, so I share it for you as a reference. I hope you can get something after reading this article.
First define a data structure for score information and use the Serializable feature to make it serializable:
Using System;using UnityEngine; namespace SK.Framework {/ score Information / [Serializable] public class ScoreInfo {/ ID / public int id; / description / [TextArea] public string description / score / public float value;}}
After the ScoreInfo class is serializable, create the ScoreProfile class to inherit ScriptableObject as an Asset asset that can be created from the menu:
Using UnityEngine; namespace SK.Framework {/ score profile / [CreateAssetMenu] public class ScoreProfile: ScriptableObject {public ScoreInfo [] scores = new ScoreInfo [0];}}
Use the ScoreIDConstant class to write all fractional ID constants, create the ScoreID feature, and use PropertyDrawer to make it selectable in the panel:
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{ /// /// 分数信息 /// [Serializable] public class ScoreInfo { /// /// ID /// [ScoreID] public int id; /// /// 描述 /// [TextArea] public string description; /// /// 分值 /// public float value; }} 数据可配置后,创建分数项Score类,声明以下字段:Flag表示该分数项的标识,注册分数项时返回该标识,用于后续获取或取消该分数项分值;Description即分数项的描述;Value表示该分数项的分值;IsObtained用于标记该分数项的分值是否已经获得。 namespace SK.Framework{ /// /// 分数项 /// public class Score { /// /// 标识 /// public string Flag { get; private set; } /// /// 描述 /// public string Description { get; private set; } /// /// 分值 /// public float Value { get; private set; } /// /// 是否已经获得分值 /// 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{ /// /// 分数组合 /// public class ScoreGroup { /// /// 组合描述 /// public string Description { get; private set; } /// /// 计分模式 /// Additive表示组合内分值进行累加 /// MutuallyExclusive表示组内各分数项互斥 获得其中一项分值 则取消其它项分值 /// public ValueMode ValueMode { get; private set; } public List Scores { get; private set; } public ScoreGroup(string description, ValueMode valueMode, params Score[] scores) { Description = description; ValueMode = valueMode; Scores = new List(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 ($"cancel the score value identified as [{flag}] in the score combination [{flag}] [{target.Description}]");} target.IsObtained = false Return true;} if (ScoreMaster.DebugMode) {ScoreMaster.LogError (there is no score item identified as [{flag}] in the $"score combination [{flag}].");} return false } namespace SK.Framework {/ scoring method / public enum ValueMode {/ cumulative / Additive, / mutually exclusive / MutuallyExclusive,}}
Finally, the score management class is written, which encapsulates the functions of Create, Obtain, Cancle and GetSum, which are used to create the score combination, obtain the score, cancel the score and obtain the total score, respectively, and realize the Editor class to visualize the score information in the Inspector panel:
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 groups = new Dictionary () # endregion # region Public Properties public static ScoreMaster Instance {get {if (instance = = null) {instance = FindObjectOfType () } if (instance = = null) {instance = new GameObject ("[SKFramework.Score]") .AddComponent (); instance.profile = Resources.Load ("Score Profile") If (instance.profile = = null & & DebugMode) {LogError ("failed to load score information configuration table.");}} 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 ($"create a score item with a score ID of [{idArray [I]}] [{info.description}] flag: {flag}");} else if (DebugMode) {LogError ($"there is no score information for ID [{idArray [I]}]] in the configuration.") }} ScoreGroup group = new ScoreGroup (description, valueMode, scores); groups.Add (description, group); if (DebugMode) {LogInfo ($"create score combination [{description}] scoring mode [{valueMode}]");} return flags } private bool ObtainValue (string groupDescription, string flag) {if (groups.TryGetValue (groupDescription, out ScoreGroup target)) {return target.Obtain (flag);} if (DebugMode) {LogError ($"there is no score combination [{groupDescription}].") } return false;} private bool CancleValue (string groupDescription, string flag) {if (groups.TryGetValue (groupDescription, out ScoreGroup target)) {return target.Cancle (flag) } if (DebugMode) {LogError ($"there is no fraction combination [{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 /// /// 创建分数组合 /// /// 分数组合描述 /// 分数组计分方式 /// 分数信息ID组合 /// 返回分数项标识符组合 public static string[] Create(string description, ValueMode valueMode, params int[] idArray) { return Instance.CreateScore(description, valueMode, idArray); } /// /// 获取分数组合中指定标识分数项的分值 /// /// 分数组合 /// 分数项标识 /// 获取成功返回true 否则返回false public static bool Obtain(string groupDescription, string flag) { return Instance.ObtainValue(groupDescription, flag); } /// /// 取消分数组合中指定标识分数项的分值 /// /// 分数组合 /// 分数项标识 /// public static bool Cancle(string groupDescription, string flag) { return Instance.CancleValue(groupDescription, flag); } /// /// 获取总分值 /// /// 总分值 public static float GetSum() { return Instance.GetSumValue(); } #endregion #region Debugger public static bool DebugMode = true; public static void LogInfo(string info) { Debug.Log($"[SKFramework.Score.Info] -->{info} ");} public static void LogWarn (string warn) {Debug.Log ($" [SKFramework.Score.Warn]-- > {warn} ");} public static void LogError (string error) {Debug.Log ($" [SKFramework.Score.Error]-- > {error} ") } # endregion} # if UNITY_EDITOR [CustomEditor (typeof (ScoreMaster))] public class ScoreMasterInspector: Editor {private SerializedProperty profile; private Dictionary groups; private Dictionary 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; groupFoldout = new Dictionary () } 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 ($"scoring mode: {(group.ValueMode = = ValueMode.Additive? "accumulate": "mutually exclusive"} "); 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; }}Using UnityEngine;using SK.Framework; public class Foo: MonoBehaviour {private string [] flags; private void Start () {flags = ScoreMaster.Create ("test", 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 ("Test", flags [0]);} if (GUILayout.Button ("B", GUILayout.Width (200f), GUILayout.Height (50f)) {ScoreMaster.Obtain ("Test", flags [1]) } if (GUILayout.Button ("C", GUILayout.Width (200f), GUILayout.Height (50f)) {ScoreMaster.Obtain ("Test", flags [2]);} if (GUILayout.Button ("D", GUILayout.Width (200f), GUILayout.Height (50f) {ScoreMaster.Obtain ("Test", flags [3]) } GUILayout.Label ($"Total: {ScoreMaster.GetSum ()}");}}
This is the end of this article on "how to make a score statistics system in Unity". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, please share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.