05丨风神界代码规范:背包右键菜单
创建日期:2025-01-11
更新日期:2025-02-04
阅读次数:58
需求
角色背包中有果子,果子有右键菜单食用。
一阶:前期一时爽,后期火葬场
public class 卡牌类 { }
public class 果子卡类 : 卡牌类 {
public void Use(角色类 X);
}
(已屏蔽)
if (X is 果子卡类 t) {
AddMenu("食用", () => t.Use(玩家));
}
这样前期简单,后期痛苦。未来道具种类越来越多,需要写几百个if,每加一个道具都要修改前台代码,会非常难受。
二阶:右键行为在类内注册
public class 卡牌类 {
public KeyValueList<string, Action> Actions { get; }
}
public class 果子卡类 : 卡牌类 {
public void Init() {
Actions.Add("食用", () => Use(玩家));
}
public void Use(角色类 A);
}
(已屏蔽)
foreach (var i in X.Actions) {
AddMenu(i.Key, i.Value);
}
这样实现了【每次添加新的道具时,不需要修改前台代码】。 但是还有问题:这只能实现【自动选择目标】。如果需要手动选择目标,比如【使用建筑卡时需要手动选择坐标位置】,那么这个结构没法实现。
三阶:选择模式
public class 卡牌类 : ITarget {
public KeyValueList<string, ITargetSelecter> Actions { get; }
}
public class 果子卡类 : 卡牌类 {
public void Init() {
Actions.Add("食用", new 吃果选择器().Add(this));
}
public class 吃果选择器 : ITargetSelecter {
public 果子卡类 果子;
public 角色类 角色;
public ITargetSelecter Add(ITarget X);(已屏蔽)
public void Clear();(已屏蔽)
public bool IsReady();
public void Exec();(已屏蔽)
public void Cancel();(已屏蔽)
}
}
(已屏蔽)
foreach (var i in X.Actions) {
AddMenu(i.Key, () => TurnInto(UIType.Select, i.Value));(已屏蔽)
}
参考LOL的技能指示器,给UI加了一个选择模式,并且支持在设置里设置快捷施法。 这个选择模式与选择器可以用于卡牌使用,也可以用于技能释放。复用性不错。 不过还有缺点:
- 快捷施法自动选择时,不知道需要哪些类型的目标,如果一个一个尝试的话比较耗费性能(反射所有字段也耗费性能)
- Clear不删除果子卡,这也太反直觉了
- 选择器里有很多可以复用的函数,不该每一个卡类里都定义一次这么多函数
四阶:压行
public class 卡牌类 : ITarget {
public KeyValueList<string, ITargetSelecter> Actions { get; }
}
public class 果子卡类 : 卡牌类 {
public void Init() {
Actions.Add("食用", new TargetSelecter<果子卡类, 角色类>(this, (果子, 角色) => 果子.Use(角色)).SetPreference<角色类>(() => 玩家));(已屏蔽)
}
public void Use(角色类 A);
}
(已屏蔽)
foreach (var i in X.Actions) {
AddMenu(i.Key, () => TurnInto(UIType.Select, i.Value));(已屏蔽)
}
定义了一个通用的选择器TargetSelecter,在库里实现【自动不清理第一位的果子卡】,并借助泛型反射(而不是字段反射)来低消耗地实现快捷施法的自动赋值。
问:库里不清理果子卡难道就不丑了吗? 答:对。【要避免丑】本质是【要避免:当我写代码时,我默认写的都是美的,导致我写错某个代码】。 库里的东西不需要我在写代码的时候关注,只需要记住【这个TargetSelecter像Func一样,多位泛型中有一位特殊】就够了,因此可以接受。