第四章、总序 方块
方块对于Minecraft的世界来说是至关重要的,它们构成了所有的地形、结构以及机器。如果您想制作一个模组,那么您可能会想要创建一些方块。本页将指导您通过创建一些方块来告诉您可以用它们做什么事情。
One Block to Rule Them All
一个方块统治所有方块
在我们开始之前,理解每一个方块在游戏里只有一个是非常重要的。一个世界是由成千上万个同一个方块在不同的地方的引用组成的。换言之,就是同一个方块同时出现了很多次。
因此,一个方块应该只在注册(https://docs.neoforged.net/docs/concepts/registries/#methods-for-registering)的时候被实例化一次。一旦这个方块被注册了,你就可以在需要的时候引用这个被注册的方块。
不像其它大多数的注册,方块可以使用的一个专用的DeferredRegister版本,它就是DeferredRegister.Blocks。DeferredRegister.Blocks基本上和DeferredRegister<Block>差不多,但也有一些小区别。
-
它们被通过DeferredRegister.createBlocks(“yourmoid”) 创建,而非常见的DeferredRegister.create(…)方法。
-
#register返回的是一个继承了DeferredHolder<Block, T>的DeferredBlock<T extends Block>。T是我们正在注册的方块的Java类的类别。
-
有一些创建方块的辅助方法,详情请参阅下文。
所以现在,让我们一起注册我们的方块吧:
//BLOCKS 是一个 DeferredRegister.Blocks。(这里我们还没有演示创建它,所以如果您此刻正在使用您的IDE做同样的事情,那么它应该会报错。这不要紧,下面我们将会解决这个问题。)
public static final DeferredBlock<Block> MY_BLOCK = BLOCKS.register(“my_block”,
()->new Block(…));
在注册了方块之后,所有新的对my_block的引用都应该使用这个常量。例如,如果你想检查给定位置的方块是否是my_block,那么这段代码应该看起来象是这样:
level.getBlockState(position)//返回在给定的世界中给定的位置被放置的方块的方块状态。
.is(MyBlockRegistrationClass.MY_BLOCK.get());
这个方法还有一个便利的效果,也就是使用block 1 == block2 是有效的,可以用来代替Java中的equals方法(当然,equals仍然是可以使用的,但那是毫无意义的,因为无论如何,它都是通过引用来进行比较的。
警告!
不要在注册流程之外调用new Block() !一旦你这么做了,事情将会变得很糟糕。
方块必须在注册表未被冻结之前创建。NeoForge将会在合适的时候为您短暂的解冻注册表并在之后重新冻结注册表。所以注册期间也是您创建方块的时间。
如果您尝试在注册表再一次被冻结之后去创建或者注册一个方块,游戏将会崩溃并报告一个空的方块,这可能会让人感到十分困惑。
如果您仍然设法获得了一个悬空方块示例,游戏将无法在同步和保存时识别出该方块并将其替换为空气。
Creating Blocks
创建方块
就像前面所说的那样,我们首先需要创建我们的DeferredRegister.Blocks:
public static final DeferredRegister.Blocks BLOCK = DeferredRegister.createBlocks(“yourmodid)”;
Basic Blocks
基础方块
对于一个不需要特殊功能的简单方块(就像圆石,木板等等)来说,可以直接使用Block类。为此,需要在注册时使用BlockBehaviour.Properties参数实例化Block。BlockBehaviour.Properties参数可以使用BlockBehaviourProperties#of方法来创建,也可以使用它的方法来自定义。这是一些很重要的方法:
-
destroyTime – 方块被破坏时需要的时间。
-
石头的破坏时间是1.5,泥土的是0.5,黑曜石的是50,而基岩的是-1(不可被破坏)。
-
explosionResistance – 方块的防爆能力
-
石头的防爆能力是6.0,泥土的是0.5,黑曜石的是1200,而基岩的是3600000。
-
sound – 设置方块在被敲打(踩踏)、破坏或者放置时的声音。
-
默认值是SoundType.STONE,更多详细信息可以查看声音页。
-
lightLevel– 设置方块发出的光亮。接受一个返回值在0-15之间的BlockState参数。
-
例如,萤石使用state->15,而火把则是state->14。
-
friction– 设置方块的光滑程度。
-
默认值是0.6,冰块是0.98。
举个例子, 一个简单的实现应该看起来像这样:
//BLOCKS is a DeferredRegister.Blocks
public static final DeferredBlock<Block> MY_BETTER_BLOCK = BLOCKS.register(
“my_better_block”,
() -> new Block(BlockBehaviour.Properties.of()
.destroyTime(2.0f)
.explosionResistance(10.0f)
.sound(SoundType.GRAVEL)
.lightLevel(state -> 7)
));
可以参阅BlockBehaviour.Properties的源代码文档来获取更多信息,也可以查看Minecraft中Blocks类来获取更多的例子。
i提醒
理解在世界中的方块和在物品栏的方块不是同一个东西是很重要的。在物品栏中看起来很像方块的物品实际上是一个BlockItem,它是一种被使用时会放置一个方块的特殊Item。
一个BlockItem必须和Block分开注册。这是因为Block不一定需要一个BlockItem,例如如果它不能被收集(比如火就是这种情况)。
这也意味着像创造物品栏或者最大堆叠数量等属性都是对相应的BlockItem的设置。
More Functionality
更多的功能
直接使用Block只能创建一个非常基础的方块。如果您想添加更多的功能,比如玩家交互或者一个与众不同的碰撞体积,您需要一个继承自Block的自定义类。Block类有需多可以重载的方法用来做各种不同的事情;查看Block、BlockBehaviour和IBlockExtension类来获取更多的信息。也可以通过查看下面的Using blocks(待施工)的部分来了解一下很常见的blocks的实例。
如果您想制作一个有不同变体的方块(例如一个有顶部、底部和两个都存在的台阶变体),您应该使用blockstates(待施工)。最后,如果您想让一个方块可以存储一些额外的数据(想想一个存储物品的箱子),您应该去使用block entity(待施工)。这里有一条经验法则,如果您的方块只有数量有限且不多的状态(最多几百个状态),使用blockstates,如果您的方块拥有无限或接近无限个状态,则使用block entity。
DeferredRegister.Blocks helpers
DeferredRegister.Blocks助手
我们在上面已经讨论了如何去创建一个DeferredRegister.Blocks以及他返回的DeferredBlock。现在,让我们一起来看看专门DeferredRegister还提供了哪些使用的程序。让我们通过#registerBlock开始吧:
public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(“yourmodid”);
public static final DeferredBlock<Block> EXAMPLE_BLOCK = BLOCKS.registerBlock(
“example”,
BLOCK::new,
BlockBehaviour.Properties.of()
);
在内部,这将通过使用properties参数来提供一个方块工厂(通常是一个构造函数),以简单地调用BLOCKS.register(“example_block”, ()-> new Block(BlockBehaviour.Properties.of())) 。
如果您想使用Block::new,您可以完全地省略工厂:
public static final DeferredBlock<Block> EXAMPLE_BLOCK = BLOCKS.registerSimpleBlock(
“example_block”,
“BlockBehaviour.Properties.of()
);
这和之前的示例一模一样,但是比起来更短一些。当然,如果您想使用Block的子类而不是Block本身,您将不得不使用之前的方法。
Resources
资源
如果您现在将您注册的方块放置在世界上,您将会发现它缺少了纹理之类的东西。这是因为纹理等内容是用Minecraft的资源系统处理的。
为了给一个方块应用一个简单的纹理,您必须添加一个方块状态(blockstate)的JSON文件以及一个模型(model)的 JSON文件以及一个纹理的PNG文件。可以在resources(待施工)的部分查阅更多的信息。