可连接方块 1.21 Fabric
本篇教程的视频
本篇教程的源代码
Github地址:TutorialMod-Connectable Block-1.21
介绍
我们前面简单介绍了一下方块状态,这次我们将使用方块状态来实现一个可连接
的方块。这个方块可以连接到其他相同的方块
但本篇教程并不是像原版的栅栏
那样,我们将实现另一种可连接方块的方式,更准确来讲应该是沙发
、长椅
这样的方块,它们也还有我们前面讲的FACING
属性
本篇教程也是从我自己目前开发的明日方舟家具模组中拿过来的实例,也是用在模组中的沙发类方块上的
当然,原本的方法是照着Mr.Crayfish
的家具模组写的,不过当时写的是照着Forge
的方法写的Fabric
的
方块类
创建SimpleFence类
1 | public class SimpleFence extends Block { |
这里我们创建了一个SimpleFence
类,继承了Block
类,这个类是我们的可连接方块的自定义类
引入FACING属性
我们这里引入了FACING
属性,然后重写一些方法
1 | public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; |
重写getPlacementState
、rotate
、mirror
方法,和前一篇教程一样
而后我们就要写可以连接的这个属性了
思考
我们怎么实现可连接呢?
我们可以设置一些字段,作为方块的方块状态
比如Type
,下面可设置单体
、左
、中
、右
四种状态
然后写一些方法来设置当前方块的Type
是什么
再在方块状态文件中用不同的Type
来返回不同的方块模型
大体的思路就是这样,其实原版很多方块状态都可以拿来参考
创建Type属性
对于我们设计的Type属性,原版没有相关的内容,这就需要我们自己来写了
这里我们创建了一个Type
的枚举类,直接写在我们的方块类中好了,将其作为一个内部类
1 | public enum Type implements StringIdentifiable { |
当然,这个Type
类需要实现StringIdentifiable
接口,并重写asString
方法
这个接口是实现用字符串提供实例
这里我们就根据我们上面的设计,写了四种Type
,分别是SINGLE
、LEFT
、MIDDLE
、RIGHT
原版一些没有的属性完全可以通过这种方法来实现,我们前面用的FACING
也是一个枚举类
设置Type属性
1 | public static final EnumProperty<Type> TYPE = EnumProperty.of("type", Type.class); |
我们在方块类中写上我们这里的属性,这里我们用EnumProperty
来设置Type
属性,因为它是一个枚举类
设置Type属性的默认值
1 | this.setDefaultState(this.getStateManager().getDefaultState().with(FACING, Direction.NORTH).with(TYPE, Type.SINGLE)); |
我们在方块类的构造方法中设置了Type
属性的默认值,这里我们设置为SINGLE
,也就是单体
当然FACING
属性也要设置默认值,这里我们设置为NORTH
,也就是北方向
重写appendProperties方法
1 |
|
记得重写appendProperties
方法,将我们的属性加入到方块状态中,包括FACING
和TYPE
重写方法
那么接下来我们就要重写一些方法,还要自己写一些方法,用这些方法来设置当前方块到底是什么Type
比如当我们的方块左右都没有相同的方块时,那它就是单体,Type
就是SINGLE
当它左边有相同的方块时,那它就是右边的,Type
就是RIGHT
当它右边有相同的方块时,那它就是左边的,Type
就是LEFT
当它左右都有相同的方块时,那它就是中间的,Type
就是MIDDLE
而我们主要要判断的就是它的左右方块是否为相同的方块
重写getStateForNeighborUpdate方法
1 |
|
这里我们重写了getStateForNeighborUpdate
方法,这个方法是当方块的邻居方块发生变化时调用的方法
然后下面的getRelatedBlockState
方法是我们自己写的
getRelatedBlockState方法
1 | private BlockState getRelatedBlockState(BlockState state, WorldAccess world, BlockPos pos, Direction direction) { |
上面的两个left
和right
是用来判断左右方向是否有相同的方块
isRelatedBlock
用于判断当前方块的邻居方块是否为相同的方块,也是我们自定义的方法
然后我们根据左右方向是否有相同的方块来设置当前方块的Type
,其逻辑就是上面我们设计的那些
direction.rotateYCounterclockwise()
是获取当前方向逆时针旋转90度的方块位置(按其朝向,为当前方块左边位置,按照我们的视角,则为方块的右边,因为我们上面放置方块是取其反向的
)
direction.rotateYClockwise()
是获取当前方向顺时针旋转90度的方块位置(同理,对于方块自身而言,是其右边位置
)
isRelatedBlock方法
1 | private boolean isRelatedBlock(WorldAccess world, BlockPos pos, Direction direction, Direction direction1) { |
因为这里要结合FACING
,所以还得判断当前方块的方向是否和邻居方块的方向相同
这样之后,我们的方块就完全写好了
下面是完整的代码
1 | public class SimpleFence extends Block { |
注册方块
随后我们要来注册方块,实例化我们的SimpleFence
类
1 | public static final Block SIMPLE_FENCE = register("simple_fence", new SimpleFence(AbstractBlock.Settings.copy(Blocks.STONE).nonOpaque())); |
加入物品栏
不要忘记加入物品栏
1 | entries.add(ModBlocks.SIMPLE_FENCE); |
数据文件
语言文件
1 | translationBuilder.add(ModBlocks.SIMPLE_FENCE, "Simple Fence"); |
这里我们在语言文件中加入了我们的方块的名字
方块状态文件
这里因为我们引入了自定义的方块状态属性,就不能使用数据生成来写了,不过也许可以?
1 | { |
这就是我们的方块状态文件,我们根据FACING
和TYPE
来返回不同的方块模型
模型文件
我们的模型文件也是拿BlockBench
制作的
一共是四个模型
simple_fence
1 | { |
simple_fence_left
1 | { |
simple_fence_right
1 | { |
simple_fence_middle
1 | { |
不想自己做模型的话就从这里复制吧
另外不要忘了对应的材质文件,而后,我们就可以启动游戏测试了