首页 > 作文

Unity 制作一个分数统计系统

更新时间:2023-04-04 00:31:47 阅读: 评论:0

项目中经常遇到分数统计的需求,例如我们执行了某项操作或做了某个题目,操作正确则计分,相反则不计分失去该项分数,为了应对需求需要一个分数统计系统。

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

using system;using unityengine; namespace sk.framework{    /// <summary>    /// 分数信息    /// </summary>    [rializable]    public class scoreinfo    {        /// <summary>        /// id        /// </summary>        public int id;        /// <summary>        /// 描述        /// </summary>        [textarea]        public string description;        /// <summary>        /// 分值        /// </summary>        public float value;    }}

scoreinfo类可序列化后,创建scoreprofile类继承scriptableobject使其作为可通过菜单创建的ast资产:

using unityengine; namespace sk.framework{    /// <summary>    /// 分数配置文件    /// </summary>    [createastmenu]    public class scoreprofile : scriptableobject    {        public scoreinfo[] scores = new scoreinfo[0];    }}

使用scoreidconstant类编写所有分数项id常量,创建scoreid特性并使用propertydrawer使其可在面板选择:

namespace sk.framework{    public aled 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(rializedproperty property, guicontent label)        {            return ba.getpropertyheight(property, label);        }         public override void ongui(rect position, rializedproperty 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>    [rializable]    public class scoreinfo    {        /// <summary>        /// id        /// </summary>        [scoreid]        public int id;        /// <summary>        /// 描述        /// </summary>        [textarea]        public string description;        /// <summary>        /// 分值        /// </summary>        public float value;    }}

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

namespace sk.framework{    /// <summary>    /// 分数项    /// </summary>    public class score    {        /// <summary>        /// 标识        /// </summary>        public string flag { get; private t; }        /// <summary>        /// 描述 2015湖南卫视小年夜春晚       /// </summary>        public string description { get; private t; }        /// <summary>        /// 分值        /// </summary>        public float value { get; private t; }        /// <summary>        /// 是否已经获得分值        /// </summary>        public bool isobtained { get; t; }         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 t; }        /// <summary>        /// 计分模式        /// additive表示组合内分值进行累加        /// mutuallyexclusive表示组内各分数项互斥 获得其中一项分值 则取消其它项分值        /// </summary>        public valuemode valuemode {小品剧本 get; private t; }         public list<score> scores { get; private t; }         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)                {                    ca valuemode.additive: target.isobtained = true; break;                    ca 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 fal;        }        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 = fal;                return true;            }            if (scoremaster.debugmode)            {                scoremaster.logerror($"分数组合 [{description}] 中不存在标识为 [{flag}] 的分数项.");            }            return fal;        }    }}
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;#endifnamespace sk.framework{public class scoremaster : monobehaviour{#region nonpublic variablesprivate static scoremaster instance;[rializefield] private scoreprofile profile;private readonly dictionary<string, scoregroup> groups = new dictionary<string, scoregroup>();#endregion#region public propertiespublic 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 methodsprivate 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}");}el 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 fal;}private booremenberl canclevalue(string groupdescription, string flag){if (groups.trygetvalue(groupdescription, out scoregroup target)){return target.cancle(flag);}if (debugmode){logerror($"不存在分数组合 [{groupdescription}].");}return fal;}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 否则返回fal</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 debuggerpublic 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 rializedproperty profile;private dictionary<string, scoregroup> groups;private dictionary<scoregroup, bool> groupfoldout;private void onenable(){profile = rializedobject.findproperty("profile");}public override void oninspectorgui(){editorguilayout.propertyfield(profile);if (gui.changed){rializedobject.applymodifiedproperties();editorutility.tdirty(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, fal);}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 aled 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("测试", 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的资料请关注www.887551.舞蹈表演专业com其它相关文章!

本文发布于:2023-04-04 00:31:45,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/37584d0cedc51e2c0c3bf582a9737ce5.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:Unity 制作一个分数统计系统.doc

本文 PDF 下载地址:Unity 制作一个分数统计系统.pdf

标签:分数   组合   分值   标识
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图