04丨风神界代码规范:背包卡牌与实体

创建日期:2025-01-11

更新日期:2025-02-04

阅读次数:62

需求

角色背包中有金币、树苗等。金币可堆叠,树苗可种植。

一阶:各种糟糕

糟糕的:背包道具无法排序

public class 背包类 {
    public Dictionary<道具类, long> 所有道具 = new();
}

糟糕的:不方便存档

public class 背包类 {
    public KeyValueList<道具类, long> 所有道具 = new();
}

糟糕的:容易出现运行时错误,出现未注册的string

public class 背包类 {
    public KeyValueList<string, long> 所有道具 = new();
}

二阶:公私分离

public class 背包类 {
    private KeyValueList<string, long> 所有道具 = new();
    public void Add(道具类 X, long Y = 1) => 所有道具.FirstOrNew(t => t.Key == X.Name).Value += Y;
}
public class 道具类 {
   public string Name;
}
public class 金币类 : 道具类 { }
public class 树苗类 : 道具类 {
    public float 当前年龄;
    public float 成熟所需;
    public void 被种植(坐标类 X);
}

不允许直接对string操作,只允许通过Add函数来操作,这样避免了程序员疏忽导致的运行时错误。

核心思想:尽量无需运行,运行就一遍过、无报错。让所有错误都在编译时出现(即VS实时静态分析),让编译无错就运行无错。 因此,不要在代码中直接对引用关系复杂的字符串直接用双引号赋值。要么不用字符串,要么用字符串就设为Private、只允许通过API来设置。

但二阶还有新的问题:二阶默认,世界中的树苗,和背包中的树苗,是一个东西。这会导致诸多问题:

  • 树苗在背包中无法堆叠,因为参数各不一致。
  • 如果比较参数是否一致、一致的堆叠,那么每一个这种【既可以在背包中存在、又可以在世界中存在】的东西都需要写一份比较逻辑,代码冗余。
  • 如果使用反射来自动比较所有参数,那么耗费性能。
  • 如果就让道具不堆叠,那么:游戏中背包中可能有上万乃至上亿个道具,例如几亿的金币、矿石、工业流水线生产的几万套建筑物(使用金丹丹界或位面级空间戒指来承载,作为升级版背包),不堆叠的话没法看。

三阶:卡牌与实体分离

public class 背包类 {
    private KeyValueList<string, long> 所有卡牌 = new();
    private List<实体类> 所有实体 = new();
    public void Add(卡牌类 X, long Y = 1) => 所有卡牌.FirstOrNew(t => t.Key == X.Name).Value += Y;
    public void Add(实体类 X) => 所有实体.Add(X);
}
public class 卡牌类 {
    public string Name;
}
public class 金币卡类 : 卡牌类 { }
public class 树苗卡类 : 卡牌类 {
    public void Use(坐标类 X);(已屏蔽)
}
public class 实体类 { }
public class 树苗类 : 实体类 {
    public float 当前年龄;
    public float 成熟所需;
}

改动:

  • 背包中的是卡牌,世界中的是实体。
  • 对某坐标使用树苗卡,在那个坐标召唤一个实体树苗。
  • 一些昂贵的背包,可以存放实体,实体不可堆叠(即:活物储物戒)。工业流水线生产的是卡牌。