Block

方块是我的世界最重要的一部分,在这一篇将介绍如何新建一个方块,注册,然后是材质加载,材质随便画了一个,称为多彩方块(colorful_block)好了

新建一个方块

首先来看Block的构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Block(BlockBehaviour.Properties p_49795_) {
super(p_49795_);
StateDefinition.Builder<Block, BlockState> builder = new StateDefinition.Builder<>(this);
this.createBlockStateDefinition(builder);
this.stateDefinition = builder.create(Block::defaultBlockState, BlockState::new);
this.registerDefaultState(this.stateDefinition.any());
if (SharedConstants.IS_RUNNING_IN_IDE) {
String s = this.getClass().getSimpleName();
if (!s.endsWith("Block")) {
LOGGER.error("Block classes should end with Block and {} doesn't.", (Object)s);
}
}
initClient();
}

可以看到,如果需要新建一个Block,需要传入一个BlockBehaviour.Properties,Properties内含方块的一些属性,比如是否能碰撞,爆炸抗性,破坏时间等,这里只介绍最简单的创建方法,其他的均为默认,新建一个类名为Dust,创建完毕后即创建好并且注册到了游戏内,在给的代码框架内中的BlockBase,已经自动的添加到了ModBlocks.BLOCKSBLOCK_ITEMS等待进一步注册

1
2
3
4
5
public class ColorfulBlock extends BlockBase{
public ColorfulBlock() {
super("colorful_block", BlockBehaviour.Properties.of(Material.DIRT));
}
}

别忘了在ModBlocks中添加以下代码实例化方块

1
public static final Block COLORFUL_BLOCK = new ColorfulBlock();

注册到游戏内

Block与Item不同,Item注册完后可以直接看到,Block除了注册自身,还需要注册一个叫做BlockItem,在给出的代码中RegistryHandler中的onRegisterItems中可以看到除了注册Item还注册了ItemBlock,在这个方法内注册了所有的BlockItem

在我的世界中,放置在世界里的叫做Block,在物品栏或者其他存储内的应为Item,为了让Block和Item有联系,存在一个类叫做BlockItem,这个类继承了Item,并且内含一个block用于存储自己所属的Block,BlockItem实现方块放置等方法,新建一个Block时,默认不包含一个BlockItem,因此除了注册Block,还需注册BlockItem

创建BlockItem

构造方法

1
2
3
4
public BlockItem(Block p_40565_, Item.Properties p_40566_) {
super(p_40566_);
this.block = p_40565_;
}

其中super代表Item,在这里可以发现,需要传入Block,以及Item.Properties来创建一个BlockItem,在BlockBase中自动添加进了ModBlock内的BLOCK_ITEMS等待注册

**有关CreativeTab**(创造模式物品栏)

在代码框架中的ExampleMod已经创建了一个最简单的创造模式物品栏,最简单的CreativeModeTab创建方法:

1
2
3
4
5
6
public static final CreativeModeTab creativeModeTab = new CreativeModeTab(模组id) {
@Override
public ItemStack makeIcon() {
return new ItemStack(Items.DIAMOND);
}
};

材质及语言

进入游戏后大概率会发现这个物体没有名字,只有一长串的字符,并且无论是拿在手里的还是实际放出的都是紫黑块,那是因为还没有定义他的名字以及材质

语言

assets/examplemod/lang下的en_us.json中加入(别忘了逗号)

1
"block.examplemod.colorful_block": "Colorful Block"

接着登录游戏就能看到他的名字变成了Colorful Block

材质

首先,需要确保你存在路径src/main/resources/assets/examplemod/

  • blockstates
  • models/block
  • models/item
  • textures/block

如果不存在,请创建,并且需要准备一张16*16 png格式的像素图,保存在textures/block下,这里提供了一张,用Aseprite随便画的,命名为colorful_block.png

在models/block中创建文件colorful_block.json

1
2
3
4
5
6
{
"parent": "block/cube_all",
"textures": {
"all": "examplemod:block/colorful_block"
}
}

在models/item下创建文件colorful_block.json

1
2
3
{
"parent": "examplemod:block/colorful_block"
}

进入游戏,会发现手上的方块已经有材质了,但是放下来后依旧是紫黑块,接下来创建的文件会解决这个问题,在blockstates下创建文件colorful_block.json

1
2
3
4
5
6
7
{
"variants": {
"": {
"model": "examplemod:block/colorful_block"
}
}
}

再次进入游戏,应该就能发现紫黑块有材质了(虽然有点丑)

BlockBench

推荐一个用来建立我的世界方块的工具,BlockBench,这个工具会根据你创建的模型自动生成你需要的json文件,这里暂时不补充,有兴趣的可以去试试

BlockState

我的世界1.7及以前的版本中,需要存储状态的块使用的是metadata(元数据,来自翻译),其是与块一起存储的额外数字,可以通过定义metadata来进行一些其他的操作

但是metadata不看源码或没注释的话是纯粹的魔法数字,没人看得懂,因此从1.8开始,BlockState取代了之前的metadata,在forge文档中举了个例子,朝东,并且激活状态的石头按钮的存储

原本为”minecraft:stone_button”,元数据为9

现在为”minecraft:stone_button[facing=east,powered=true]”

第二种更为实用,对于BlockState,每一种状态组合在游戏创建初期就已经确认,不可变,因此可以用(==)来检查两个状态是否相等

如何创建一种状态属性

官方已经给好了四种基本状态,为

  • IntegerProperty
  • DirectionProperty
  • EnumProperty
  • BooleanProperty

分别是整数属性,方向属性,Enum属性,布尔属性,需要创建这些类型的可以直接new,对于他们各自的构造方法在此不细究,官方文档给的较为详细

如果需要创建自己的状态,需要继承Property<?>类,在这里面实现一些方法,具体实现可以参考源码的实现完成的属性

注册到Block中

当确定需要一个状态时,需要覆写createBlockStateDefinition(StateDefinition.Builder)来加入,通过调用registerDefaultState来改变默认状态,在这里同样使用之前的first_block,但是改为了一个类,在这里给出覆写以及更改默认状态后的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ColorfulBlock extends BlockBase{
public static final BooleanProperty BOOLEAN_PROPERTY = BooleanProperty.create("example_boolean");;

public ColorfulBlock() {
super("colorful_block", BlockBehaviour.Properties.of(Material.DIRT));
this.registerDefaultState(
this.stateDefinition.any()
.setValue(BOOLEAN_PROPERTY, false)
);
}

@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateBuilder) {
stateBuilder.add(BOOLEAN_PROPERTY);
}

}

如果需要覆盖放置块时的BlockState,可以通过覆写getStateForPlacement方法,默认为方块的默认状态,写完后在游戏内按F3,对着方块在右边即可看到有一个example_boolean:false

与blockstates中的json文件交互

在ColorfulBlock中覆写getStateForPlacement语句,这样能修改放置下来的布尔属性

1
2
3
4
5
6
7
8
9
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
if(context.getClickedPos().getX()%2==0||context.getClickedPos().getZ()%2==0){
return defaultBlockState().setValue(BOOLEAN_PROPERTY,true);
}
return defaultBlockState().setValue(BOOLEAN_PROPERTY,false);
}

意思为只有X和Z坐标为单数时,布尔属性为false,下面修改blockstates中的colorful_block.json为

1
2
3
4
5
6
7
8
9
10
{
"variants": {
"example_boolean=true": {
"model": "examplemod:block/colorful_block"
},
"example_boolean=false": {
"model": "minecraft:block/oak_log"
}
}
}

设置完成后,进入游戏即可看到,当X和Z坐标为单数时,模型变为了橡木原木,其他模型不变(当然,如果你是加入语句之前放置的,之前的方块依旧为false,也就会渲染成橡木)

image-20220221093606267

除了简单的判断example_boolean,还有其他的方法来判断多种属性(when… apply),以及设置旋转,材质锁定等,具体见此链接

交互

源码中的Block继承了BlockBehaviour,在里面有很多的交互方法以及获取一些值,forge文档中给出了不少例子可以作为参考

在此处只打出这些方法名,可以通过网页搜索看看有没有需要的,日后可能会拓展其中一些

  • attack
  • canBeReplaced
  • canSurvive
  • defaultDestroyTime
  • defaultMaterialColor
  • entityInside
  • getAnalogOutputSignal
  • getBlockSupportShape
  • getCollsionShape
  • getDirectSignal
  • getDrops
  • getFluidState
  • getInteractionShape
  • getLightBlock
  • getLootTable
  • getMaxHorizontalOffset
  • getMaxVerticalOffset
  • getMenuProvider
  • getOcclusionShape
  • getOffsetType
  • getPistonPushReaction
  • getRenderShape
  • getSeed
  • getShadeBrightness
  • getShape
  • getSignal
  • getVisualShape
  • hasAnalogOutputSignal
  • isAir
  • isCollsionShapeFullBlock
  • isPathfindable
  • isSignalSource
  • mirror
  • neighborChanged
  • onPlace
  • onProjectileHit
  • onRemove
  • randomTick
  • rotate
  • skipRendering
  • spawnAfterBreak
  • tick
  • triggerEvent
  • updateIndirectNeighbourShapes
  • updateShape
  • use
  • useShapeForLightOcclusion