基础家具
903 字约 3 分钟
2024-12-27
思路
基础家具不具备实际的使用功能,仅作为一种展示。但是为了提供一定的互动性(并且便于拆除),其最好是具备碰撞箱。
模型放置
在 自定义模型方案 中我们通过对展示框自定义模型来实现家具在物品栏的展示, 现在我们需要考虑如何将家具放置出来,这样才具备实际的展示效果。
Minecraft 1.19.4 版本中加入的 展示实体(Display),非常适合用来显示家具。 展示实体自身没有移动行为,不会受到伤害,不会发出声音,不会阻碍方块放置,也不会将玩家或其他实体推开自己所在的位置。
我们可以使用 物品展示(ItemDisplay) 来展示我们修改过模型的展示框物品,这样便能实现在游戏中放置一个自定义模型的效果。
碰撞箱
展示实体不具备碰撞箱且无法被选中,因此存在一个问题:玩家无法将其拆除。
考虑到家具本身被设计为一种方块,所以采用一个原版游戏的方块来代替家具的碰撞箱最为合适,该方块应当具备以下特性:
- 透明:这样不会与家具的展示实体重叠;
- 带有碰撞箱:这样玩家可以点击并拆除家具,同时避免穿模;
- 自身不发光:保证展示实体模型光照效果不受影响;
综上考虑,屏障方块是一个最佳的选择。 我们需要在玩家放置家具时在对应的位置生成一个展示实体和一个屏障方块,两样相结合实现模拟的家具方块的效果。
不过这样引入了一个新的问题,屏障方块普通玩家无法拆除。为了解决这个问题,我们可以引入一个自定义工具,用于拆除家具。 也就是删除展示实体和屏障方块,不用担心玩家利用这个工具破坏普通的屏障方块,因为我们可以很轻松的在代码中判断一个屏障方块是否是被用作家具。
实现 FurnitureBlock.java
首先当我们准备放置一个家具方块时需要先创建一个 FurnitureBlock 对象,传入家具物品栈和放置位置:
private final FurnitureItemStack furnitureItemStack;
private final Location location;
private final NamespacedKey key;
public FurnitureBlock(FurnitureItemStack furnitureItemStack, Location location) {
this.furnitureItemStack = furnitureItemStack;
this.location = location;
this.key = new NamespacedKey("furniture", LocationToHash(location));
}
在这里我们构造了一个 NamespacedKey ,其名称为 furniture:位置的哈希值
,稍后我们会将此 NamespacedKey 保存在 PDC 中用于检索数据。
在需要放置方块的时候只需要按照前文的思路即可:
location.getBlock().setType(getPlaceholderBlockType()); // 放置一个屏障方块
ItemDisplay itemDisplay = (ItemDisplay) location.getWorld().spawnEntity(location.add(0.5, 0.5, 0.5), EntityType.ITEM_DISPLAY); // 创建一个展示实体
itemDisplay.setItemStack(furnitureItemStack); // 设置展示实体的物品为家具物品
最后将此家具方块的 NamespacedKey 与展示实体的 UUID 值保存在 PDC 中:
location.getWorld().getPersistentDataContainer().set(key, PersistentDataType.STRING, itemDisplay.getUniqueId().toString());
这么做可以有两个作用:
- 当想要判断一个屏障方块是否是家具时,只需要根据其坐标构建一个 NamespacedKey 并检查 PDC 中是否存在此键;
- 当想要检索一个坐标的展示实体时,同样构建一个 NamespacedKey 并从 PDC 中获取其值,然后根据 UUID 获取展示实体;