起因
最近项目需要做游戏的 GM 指令,思前想去,想了几个方案后, 最后决定使用 UnityIngameDebugConsole
提供的 GM 指令,然后封装一个热更可用的组件
尝试的方案
iOS 捷径
之前我很喜欢使用捷径来做一些游戏的 GM 指令
但是当区分渠道、服务器、还需要查表时,这个方案做起来就非常难以维护,而且对安卓手机没有找到合适的处理方式
GM UI
还有一些会把GM 指令在游戏中做成图形化的UI, 点击A 按钮触发 xxxx
这个方案需要设计一个如何触发 GM UI 的逻辑,而且如果增删指令,还要对 UI 布局进行调整,就很烦
UnityIngameDebugConsole
大佬写的这个组件,在真机测试碰到一些bug时,非常非常非常救命,而且本身支持 Executing Commands
,而且用起来也非常简单,下面我主要讲一下如何实现
具体实现
使用效果如下
gm id // 展示用户ID
gm money 5000 // 增加5000金币
ConsoleMethod
这里之所以要写这么多是因为有些指令不需要额外的参数,有些需要,而且要防止策划或其他人员使用时,没有正确大小写导致不能正确执行
namespace ETModel {
public class DebugConsoleGM {
[ConsoleMethod("GM", "GM Code")]
public static void Excute(string command, string value = null) {
Game.EventSystem.Run(EventIdType.DebugConsoleGM, command, value);
}
[ConsoleMethod("gm", "GM Code")]
public static void Excute1(string command, string value = null) {
Game.EventSystem.Run(EventIdType.DebugConsoleGM, command, value);
}
[ConsoleMethod("GM", "GM Code")]
public static void Excute2(string command) {
Game.EventSystem.Run(EventIdType.DebugConsoleGM, command, string.Empty);
}
[ConsoleMethod("gm", "GM Code")]
public static void Excute3(string command) {
Game.EventSystem.Run(EventIdType.DebugConsoleGM, command, string.Empty);
}
}
}
这里需要注意在
ETModel
中EventIdType
类里面增加对应的类型
Hotfix 监听
这里的监听很简单,在热更中创建一个 ETModel.EventIdType
的事件即可
这里监听到后,把所有的属性和参数传给
GMCodeComponent
,进行处理
namespace ETHotfix {
[Event(ETModel.EventIdType.DebugConsoleGM)]
public class DebugConsoleGMHandler : AEvent<string, string> {
public override void Run(string commond, string value) {
try{ Game.Scene.GetComponent<GMCodeComponent>().Handle(commond, value); }
catch(Exception e){ Log.Error(e); }
}
}
}
IGmCodeHandler
我们给所有的指令提供一个接口
namespace ETHotfix {
public interface IGMCodeHandler {
void Handle(string value);
}
}
展示ID 的指令示例
这里我同样创建了一个 GMCodeDefine
,用于定义游戏中所有GM指令的名字,这个部分就不贴了
namespace ETHotfix {
[GMCode(GMCodeDefine.ID)]
public class GMCode_ID_Handler : IGMCodeHandler {
public void Handle(string value) {
try{
// show id
}
catch(Exception e){ Log.Error(e); }
}
}
}
GMCodeComponent
这里同样对传过来的 commond
进行了 ToUpper
处理,防止其他人错误的书写了大小写
注意在 GMCodeDefine 中定义的属性值最终都是大写噢
namespace ETHotfix { [ObjectSystem] public class GMCodeComponentAwakeSystem : AwakeSystem<GMCodeComponent> { public override void Awake(GMCodeComponent self) { self.Awake(); } } public class GMCodeComponent : Component { private readonly Dictionary<string, IGMCodeHandler> _gmCodes = new Dictionary<string, IGMCodeHandler>(); public void Awake() { _gmCodes.Clear(); List<Type> types = Game.EventSystem.GetTypes(); foreach(Type type in types){ object[] attrs = type.GetCustomAttributes(typeof(GMCodeAttribute), false); foreach(object attr in attrs){ GMCodeAttribute gmCodeAttribute = (GMCodeAttribute) attr; object obj = Activator.CreateInstance(type); IGMCodeHandler iGMCode = obj as IGMCodeHandler; if(iGMCode == null){ Log.Error(
quot;{obj.GetType().Name} is not inherit IGMCodeHandler");
continue;
}if(_gmCodes.ContainsKey(gmCodeAttribute.CodeName)){ continue; }
_gmCodes.Add(gmCodeAttribute.CodeName, iGMCode);
}
}
}public void Handle(string commond, string value) {
try{
commond = commond.ToUpper();Log.Debug(
quot;commond = {commond}, value = {value}");
if(_gmCodes.ContainsKey(commond)){ _gmCodes[commond].Handle(value); }
}
catch(Exception e){ Log.Error(e); }
}
}
}
总结
这个方案对程序很友好,如果区分渠道、服务器、查表或者实时在游戏中显示,都可以在每一个指令中做相应的控制,增删改也很方便
不过需要给使用人员维护一张指令表,且有一定的学习成本