本篇教程由作者设定未经允许禁止转载。

模块化机械:社区版 从入门到入土 —— Part.Extra.1 GeckoLib 模型/动画

本篇教程皆在展示模块化机械:社区版的特殊功能。

本教程主要使用的模组为模块化机械:社区版 - 1.11.1-r53、CraftTweakerGeckoLib

教程目录:

环境准备

本教程强烈推荐使用 Visual Studio Code(以下简称 VSCode),可以大大减少你的魔改工作量。

使用 VSCode,你可以利用它的强大的功能来更快的完成复杂的操作,同时拥有代码提示,大大减少代码阅读难度和出错率,同时可以安装插件来扩展功能,使其更加强大。

阅读本教程即代表你已熟悉 ZenScript 的大部分高级运用,并且已经了解基本的机械创建与配方创建。


要创建模型,你需要使用 BlockBench 来制作和导出模型。

要加载模型文件,你还需要安装 ResourceLoader 或其他可以加载外部资源包的模组。

模型格式为基岩版模型。

阅读本教程即代表你已熟悉 ZenScript 的大部分高级运用,并且熟悉基岩版模型文件的格式、贴图、动画格式。

警告:GeckoLib 不支持 AMD 显卡,请谨慎考虑。

介绍

从 模块化机械:社区版 R53 版本起,玩家可以使用 ZenScript 脚本为机械设置一系列的自定义模型和动画。

本篇教程将为玩家提供一系列完整的使用教程。

模型文件准备

绑定模型总计需要三个文件,分别为模型文件模型贴图模型动画文件,名称依次为 xxx.geo.jsonxxx.pngxxx.animation.json

模型文件

在 BlockBench 导出模型时务必选择基岩版模型

导出路径通常为 “.minecraft/resources/modularmachinery/geo/xxx.geo.json”,也可自行选择其他路径(但不可超出 ./minecraft/resource 范围)。

注意:路径选择一定要仔细检查,如果文件不存在则可能会导致游戏加载崩溃。

Part.Extra.1 GeckoLib 模型/动画 —— 模块化机械:社区版 从入门到入土-第1张图片BlockBench 中的导出格式选择

模型贴图

在纹理处右击并选择《另存为》。

导出路径通常为 “.minecraft/resources/modularmachinery/textures/blocks/xxx.png”,也可自行选择其他路径(但不可超出 ./minecraft/resource 范围)。

Part.Extra.1 GeckoLib 模型/动画 —— 模块化机械:社区版 从入门到入土-第2张图片贴图导出操作

模型动画文件

在动画模式下,右击界面左方的动画列表空区,点击保存所有动画。

导出路径通常为 “.minecraft/resources/modularmachinery/animations/xxx.animation.json”,也可自行选择其他路径(但不可超出 ./minecraft/resource 范围)。

注意:如果没有动画也需要导出一个空的动画文件,文件不存在可能会导致游戏崩溃。

Part.Extra.1 GeckoLib 模型/动画 —— 模块化机械:社区版 从入门到入土-第3张图片模型动画导出操作

模型注册

在为机械配置模型前,我们需要将模型注册到游戏中。

使用 ZenScript 脚本来注册模型。

注:一个模型可以被绑定到多个机械。


示例脚本:

import mods.modularmachinery.GeoMachineModel; // 导包

GeoMachineModel.registerGeoMachineModel("model_name", // 模型名称
    "modularmachinery:geo/model.geo.json", // 模型文件路径
    "modularmachinery:textures/model.png", // 模型贴图路径
    "modularmachinery:animations/model.animation.json" // 模型动画路径
);

脚本中的路径为演示路径,实际路径请参考自身环境的路径调整。


模型绑定

要为机械绑定模型,需要使用 ZenScript 脚本进行操作。

示例脚本:

import mods.modularmachinery.MachineModifier;

// ...此处省略注册模型部分

//                                 机械名称          模型名称(必须先注册后使用)
MachineModifier.setMachineGeoModel("machine_name", "model_name");

重载脚本或重启游戏,若脚本无报错,我们已经成功的为机械绑定了自定义模型。

在游戏中建造机械,成型后,即可正确渲染我们的自定义模型。


成功示例(模型文件版权归模型作者 WI-8614-ice 所有,未经授权严禁转载):

Part.Extra.1 GeckoLib 模型/动画 —— 模块化机械:社区版 从入门到入土-第4张图片一个成型的机械控制器的模型渲染

机械组件方块模型隐藏(可选)

有时候,我们可能需要为模型添加更多的细节,但是这可能会和机械原有的结构冲突,这个时候我们可以为机械设置隐藏组件的选项。

注意:要使用此功能,必须安装 Multiblocked 或者此模组(两者互相不兼容)

打开要隐藏组件的机械的文件,在文件中添加下图所示的配置:

Part.Extra.1 GeckoLib 模型/动画 —— 模块化机械:社区版 从入门到入土-第5张图片"hide-components-when-formed": true配置完成后,重载脚本或重启游戏,此时当机械成型后,机械就会自动隐藏所有结构组件的模型渲染。

模型动画

现在我们完成了对机械的模型绑定,但此时还不能能够使起动起来。

接下来我们将使用 ZenScript 为机械设置动画。


示例脚本:

import mods.modularmachinery.MMEvents;

import mods.modularmachinery.ControllerModelAnimationEvent;

// ...此处省略注册模型部分
// ...此处省略模型绑定部分

MMEvents.onControllerModelAnimation("machine_name", function(event as ControllerModelAnimationEvent) {
    val ctrl = event.controller;
    
    // 检查机械是否正在工作。
    if (ctrl.isWorking) {
        // 为模型设置名为 "working" 的动画,只播放一次。
        event.addAnimation("working");
    } else {
        // 为模型设置名为 "idle" 的动画,并且会循环播放。
        event.addAnimation("idle", true);
    }
});

此段脚本会使机械在工作时运行名为 "working" 的动画,并且会循环播放,反之会运行 "idle" 动画,并且会循环播放。

除此自外,你也可以自行判断机械的各种状态,为机械播放不同的动画。

注意:动画名称必须和 BlockBench 中的动画名完全对应,否则可能会导致游戏崩溃。

动态模型切换

有时候我们可能会对机械做出一些升级,为机器更换上更高级或者更炫酷的模型,这个时候我们可以设置动态模型切换功能。

示例脚本:

import mods.modularmachinery.MMEvents;

import mods.modularmachinery.ControllerModelGetEvent;

// ...此处省略注册模型部分
// ...此处省略模型绑定部分

MMEvents.onControllerModelGet("machine_name", function(event as ControllerModelGetEvent) {
    val ctrl = event.controller;
    
    if (ctrl.hasModifierReplacement("replacement_1") {
        event.modelName = "model_name_upgraded";
    }
});

注意:如果模型名称对应的模型未注册,则不会使用该模型,且会被自动回滚至机械的默认模型。

ControllerModelAnimationEvent 高级运用

本段提供了关于机械模型动画事件的更多可用的高级方法。

/**
 * 为模型添加一个动画,只运行一次。
 * 会按照添加动画的顺序来运行动画。
 */
@ZenMethod
public void addAnimation(String animationName);

/**
 * 为模型添加一个动画,并设置其是否会循环运行。
 * 会按照添加动画的顺序来运行动画。
*/
@ZenMethod
public void addAnimation(String animationName, boolean loop);

/**
 * 类似 addAnimation(String animationName),但是它会覆盖先前所有添加的动画。
*/
@ZenMethod
public void setAnimation(String animationName);

/**
 * 类似 addAnimation(String animationName, boolean loop),但是它会覆盖先前所有添加的动画。
*/
@ZenMethod
public void setAnimation(String animationName, boolean loop);

/**
 * 获取当前模型的注册名称。
 */
@ZenGetter("currentModelName")
public String getCurrentModelName();

/**
 * 获取当前模型的过渡长度(单位:Tick)
 */
@ZenGetter("transitionLengthTicks")
public double getTransitionLengthTicks();

/**
 * 设置当前模型的过渡长度(单位:Tick)
 */
@ZenSetter("transitionLengthTicks")
public void setTransitionLengthTicks(double transitionLengthTicks);

/**
 * 获取当前机械的动画运行状态。
 * 0 为运行,1 和其他数值为停止。
 */
@ZenGetter("playState")
public int getPlayState();

/**
 * 设置当前机械的动画运行状态。
 * 0 为运行,1 和其他数值为停止。
 */
@ZenSetter("playState")
public void setPlayState(final int playState);

/**
 * 获取当前机械正在运行的动画名称。
 */
@Nullable
@ZenGetter("currentAnimationName")
public String getCurrentAnimationName();

/**
 * 获取当前机械正在运行的动画速度。
 */
@ZenGetter("animationSpeed")
public double getAnimationSpeed();

/**
 * 获取当前机械的动画进度(单位 Tick)。
 */
@ZenGetter("animationTick")
public double getAnimationTick();

/**
 * 获取当前机械的动画状态。
 * 0 为运行,1 为切换中,2 为停止中。
 */
@ZenGetter("animationState")
public int getAnimationState();

/**
 * 待测试。
*/
@ZenGetter("limbSwing")
public float getLimbSwing();

/**
 * 待测试。
*/
@ZenGetter("limbSwingAmount")
public float getLimbSwingAmount();

/**
 * 待测试。
*/
@ZenGetter("partialTick")
public float getPartialTick();

/**
 * 待测试。
*/
@ZenGetter("moving")
public boolean isMoving();