本篇教程的视频
(待发布)
本篇教程的源代码
(待发布)
简介
这篇教程我们来制作一个高级物品——探矿器(Prospector)
可以用它来寻找矿物
另外,我们再额外加一个功能:当玩家按下Shift时,探矿器执行精确搜索;否则执行5×5范围搜索
探矿器
自定义物品
那么这个东西是一个高级物品,所以我们需要创建一个自定义物品类ProspectorItem,继承自Item类
1 2 3 4 5
| public class ProspectorItem extends Item { public ProspectorItem(Properties pProperties) { super(pProperties); } }
|
那么,接下来要重写物品使用的方法,因为一般的物品,就像我们之前写的那些物品,并没有使用的效果
物品的使用方法有很多,useOn是使用在方块上的方法,use方法则是常规的右键使用方法
比如一些食物类物品,都是重写的use方法;投掷物像雪球、末影珍珠等,都是重写的use方法
这里我们重写useOn方法,你同样可以重写use方法来实现类似的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| @Override public InteractionResult useOn(UseOnContext pContext) { BlockPos pos = pContext.getClickedPos(); Player player = pContext.getPlayer(); Level level = pContext.getLevel();
if (!level.isClientSide()) { boolean found = false; if (!Screen.hasShiftDown()) { for (int i = 0; i <= pos.getY() + 64; i++) { for (int j = 0; j < 5; j++) { for (int k = 0; k < 5; k++) { BlockPos pos1 = pos.below(i).north(j).east(k); BlockState blockState = level.getBlockState(pos1); String name = blockState.getBlock().getName().getString();
if (isCorrectBlock(blockState)) { player.sendSystemMessage(Component.literal("Found" + name + "!")); found = true; break; } } } } if (!found) { player.sendSystemMessage(Component.literal("No ore found!")); } } else { for (int i = 0; i <= pos.getY() + 64; i++) { BlockPos pos1 = pos.below(i); BlockState blockState = level.getBlockState(pos1); String name = blockState.getBlock().getName().getString();
if (isCorrectBlock(blockState)) { player.sendSystemMessage(Component.literal("Found" + name + "!")); found = true; break; } } if (!found) { player.sendSystemMessage(Component.literal("No ore found!")); } } pContext.getItemInHand().hurtAndBreak(1, player, EquipmentSlot.MAINHAND); return InteractionResult.SUCCESS; } return super.useOn(pContext); }
private boolean isCorrectBlock(BlockState blockState) { if (blockState.is(Blocks.DIAMOND_ORE) || blockState.is(Blocks.DEEPSLATE_DIAMOND_ORE)) { return true; } else { return false; } }
|
这里我将代码全部放了出来,我们一点点来看
首先是获取玩家点击的方块位置pos,玩家对象player,以及世界对象level
然后我们判断当前代码是否在服务端执行,一些逻辑运算,都是交给服务器去执行的,就算是单人游戏,实际上也是有一个内置的服务器在运行的
客户端主要负责渲染和显示
接下来我们定义了一个found变量,用于标记是否找到了矿物,这个是为找到一个矿物就停止搜索做准备的
然后我们判断玩家是否按下了Shift键,如果没有按下Shift键,就执行5×5范围搜索
Shift键是否按下,可以通过Screen.hasShiftDown()方法来判断,这是一个已经封装好的方法
后面就是一堆循环了,我们从玩家点击的方块位置开始,向下搜索,直到世界底部
我们也封装了一个isCorrectBlock方法,用于判断当前方块是否是我们想要找的矿物
当然这里的矿物只写了钻石矿,因为这个教程是准备和后面一期的Tag教程配合使用的,后面我们会把所有矿物都放到一个Tag里,再来判断
如果找到了矿物,我们就给玩家发送一条消息,告诉他找到了什么矿物;如果没有找到矿物,我们也给玩家发送一条消息,告诉他没有找到矿物
最后,我们让探矿器损坏1点耐久值,然后返回InteractionResult.SUCCESS,表示使用成功
整体上的逻辑并不复杂,主要是循环和判断
至于这个循环是否很耗费性能,其实是没关系的,因为这个物品的使用频率并不会很高,而且搜索的范围也不是特别大,和遍历区块相比,影响可以忽略不计
注册物品
接下来我们在ModItems类中注册这个物品
1 2
| public static final DeferredItem<Item> PROSPECTOR = ITEMS.register("prospector", () -> new ProspectorItem(new Item.Properties().durability(127)));
|
这里我们注册了一个名为PROSPECTOR的物品,耐久值为127,不过可以使用128次
添加到物品栏
然后,还要把这个物品添加到物品栏中
1
| output.accept(ModItems.PROSPECTOR);
|
数据文件
同样,我们还是使用数据生成来添加各种数据文件
语言文件
1
| add(ModItems.PROSPECTOR.get(), "Prospector");
|
模型文件
1
| basicItem(ModItems.PROSPECTOR.get());
|
材质文件
最后还得将材质文件放到正确的位置