项目中经常遇到分数统计的需求,例如我们执行了某项操作或做了某个题目,操作正确则计分,相反则不计分失去该项分数,为了应对需求需要一个分数统计系统。
首先定义一个分数信息的数据结构,使用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 条评论) |