1.1. 所谓的“实体模型”
但多数时候,实体的渲染只是一堆不同尺寸的长方体的平移、旋转及缩放操作而已,对于原版生物实体来说这个情况尤为普遍。为此 Minecraft 搞出来了一套不同寻常的“模型”系统。这套系统是完全写死在代码里的,但它包含了大量可以用其他平台无关的数据交换格式表示的数据。
社区有时候会管这种模型叫“Java 模型”,实际上这个东西只有 Minecraft 在用,而且它也不是严格意义上的模型,因为它还包括了控制某些部件旋转的逻辑,这已经不是一个静态的模型会有的东西了。因此,“Java 模型”的叫法并不严谨。
1.1.1. ModelBase
观察 RenderLiving
的构造器,它要求三个参数:
RenderManager
。这个所有的Render
都有。ModelBase
。float
,它用于控制实体阴影的尺寸。
那个 ModelBase
便是这个模型系统的起点了。所有 RenderLiving
的派生类中,都向这个构造器中传入了一个特定的 ModelBase
的实现。
public class MyEntityModel extends ModelBase {
@Override
public void render(Entity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scale) {
// 具体的渲染逻辑全部在此发生。
}
@Override
public void setRotationAngles(float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scaleFactor, Entity entity) {
// 你应该注意到了,原版很多实体是有写实的走路动画效果的。
// 这个方法可以用来更新当前模型的信息,是实现类似走路动画等动画效果的基础。
}
}
1.1.2. ModelRenderer
ModelRenderer
实际上代表了一堆要被渲染长方体的集合。这些长方体可以是独立存在的(ModelBox
),也可以是另一堆长方体(是的,Composite pattern,一个 ModelRenderer
下也可以包含一堆 ModelRenderer
)。这些长方体们受统一的位移、旋转中心与旋转角度控制。
通常你会在你的 ModelBase
的实现中声明一堆 ModelRenderer
的字段。这也是为什么会出现 Techne、Tabula 等工具的原因——手写这种东西迟早会累死人。就像下面这样:
public class MyEntityModel extends ModelBase {
private final ModelRenderer part1;
private final ModelRenderer part2;
private final ModelRenderer part3;
// ...
// 省略剩下的 ModelRenderer 的声明
public MyEntityModel() {
this.part1 = new ModelRenderer(this, ...);
// 省略 setup
this.part2 = new ModelRenderer(this, ...);
// 省略 setup
this.part3 = new ModelRenderer(this, ...);
// 省略 setup
}
@Override
public void render(Entity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scale) {
// 省略相关 GlStateManager 的调用
this.part1.render(scale);
this.part2.render(scale);
this.part3.render(scale);
// 省略相关 GlStateManager 的调用
}
@Override
public void setRotationAngles(float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scaleFactor, Entity entity) {
// 根据实际情况更新数据。
}
}