Skip to main content

1.3 Item 类和 ItemStack 类

前面两节叙述了加入普通自定义物品(item)的大致流程。现在深入一下更抽象的层面,考虑这些物品背后的类,以便我们进一步对它们进行自定义。

首先,很方便理解的是 Item 类,就是规定每种物品属性的类。细心的同学可能会提问,我们之前创建的 ObsidianIngot 这个类在游戏的框中显示的数量呢?一组应该是多少个呢?Item 类都没有定义。

这是因为,设计者考虑到 item 的有些信息不会因为数量、耐久等参数的改变而改变,例如:

  • 使用/放置(左键/右键)的行为;
  • 在客户端上显示的名称及 Tooltip;
  • 合成配方;
  • et cetera;

这些抽象的属性都在 Item 类中得到定义;而数量、是否有/有多少耐久等信息,就单独提出去打包为一个类,其名曰 ItemStack。游戏中,玩家的物品栏、背包、手持物品等,都是 ItemStack 的实例

所以,可以将 ItemStackItem 的关系看作类的聚集,在对 ItemStack 可以调用 getItem() 实例方法来获得其中含有的 Item 对象。

享元

另外有个极其重要的概念——“享元(Flyweight Pattern)”,即一种特定物品只对应一个实例,而 Item 就是一个享元。这意味着,以 Apple 类为例,你在游戏里见到所有苹果都是 Apple 类的唯一实例。正因如此,我们在编写 mod 中,可以直接用 ==(即 <ItemStack_obj>.getItem() == <Item_obj>)来判断 Item 种类,不用担心 == 比较的是地址。

Item.AIR

还有一件事,由于 ItemStacknon-null 的属性,永远是非空引用,所以 MC 中 “空的” 栏的 ItemStack 所含的 Item 对象是个特殊对象:Items.AIR。判断 ItemStack 对应的栏目物品是否为空时,应该使用专用的实例函数 isEmpty(),不能直接判断是否为 null