Skip to content

工厂、方块通性、消耗器、绘制器

"从矿石到成品的魔法,都发生在一个方块里。"

物品和流体只是躺在仓库里的原材料,真正让世界运转起来的是方块(Block)。这一章我们要造出第一个"会干活"的方块——一个自动消耗铜、吐出强化铜的工厂,并在过程中揭开三张隐藏的网:所有方块共享的通性、决定"吃什么"的消耗器、决定"长什么样"的绘制器

学完这一章,你就能随手捏出任意配方、任意外观的加工厂。

本章涉及的源码mindustry/world/Block.javamindustry/world/blocks/production/GenericCrafter.javamindustry/world/consumers/mindustry/world/draw/mindustry/mod/ContentParser.java


方块通性:所有方块的公共底盘

在 Mindustry 里,所有方块都继承自同一个基类 Block(源码 world/Block.java)。这意味着无论你是工厂、炮塔还是传送带,都共享一大批"通性"字段。我们先扫一遍最常用的:

字段类型默认值说明
type字符串Block方块类型,决定它"是什么"。工厂填 GenericCrafter
size1~8 整数1占地边长(格)
health整数按配方算血量,默认由建材自动计算
requirements数组[]建造所需物品,如 [copper/20]
category字符串distribution建造菜单里的分类
solid布尔false是否阻挡单位与子弹
destructible布尔false是否可被摧毁
hasItems布尔false是否有物品槽
hasLiquids布尔false是否有流体槽
hasPower布尔false是否接入电网
itemCapacity整数10物品槽容量
liquidCapacity浮点-1流体槽容量(-1 表示自动按消耗算)
buildVisibility字符串hidden是否出现在建造菜单(shown/hidden/debugOnly
rebuildable布尔true被毁后能否重建
canOverdrive布尔true能否被超速装置加速
configurable布尔false玩家能否点击配置
drawArrow布尔true是否画输入方向箭头
buildTime浮点-1建造时间(-1 表示按造价自动算)

两个自动化的温柔

  • 只要写了 requirements,方块就会自动变为可见可建造(源码在 ContentParser 里把 buildVisibilityhidden 抬到 shown)。所以初学者常常只写 requirements 就够了。
  • healthbuildTime 不写也行,游戏会按 requirements 里的建材自动推算。

消耗器:决定方块"吃什么"

v8 的消耗系统是一次大改。方块吃的东西——电、物品、流体——不再写成零散的 consumePower/consumeItems 字段,而是统一塞进一个 consumes 对象里(源码 ContentParser.readBlockConsumers)。

对照《饱和火力》的 silicon-smelter.json(它给原版硅炉加了电力消耗):

json
{
  "details": "兄弟,借个火?",
  "craftTime": 40,
  "consumes": {
    "power": 0.25
  }
}

consumes 对象里可用的键:

写法示例含义
powerpower: 0.25每 tick 消耗的电力(浮点)
itemsitems: [copper/2, lead/1]消耗多种物品
itemitem: coal消耗单种物品(默认 1 个/次)
liquidsliquids: [water/0.1]消耗多种流体
liquidliquid: water消耗单种流体
coolantcoolant: { amount: 0.1 }作为冷却液消耗(用于降温方块)
itemsBoost / liquidsBoostitems/liquids消耗后给方块"增益",而非必需
powerBufferedpowerBuffered: 100消耗"缓冲电力"(蓄电型)

v7 → v8 的坑

旧教程教的顶层字段 consumePowerconsumeItemsconsumeLiquid 在 v8 里已经不存在了(源码里只剩一个 consPower 内部字段)。如果你照搬旧写法,会收到 "Unknown field" 警告。统一改用 consumes: { ... } 对象


工厂:GenericCrafter

现在认识我们的主角——通用工厂(GenericCrafter),源码 world/blocks/production/GenericCrafter.java。它做一件事:满足消耗条件后,每隔 craftTime 就产出一次东西。

它继承 Block 的所有通性,再追加下面这些字段:

字段类型默认值说明
craftTime浮点80单次生产耗时(tick,60 tick = 1 秒)
outputItem / outputItems栈/数组产出的物品(单/多)
outputLiquid / outputLiquids栈/数组产出的流体(单/多)
liquidOutputDirections整数数组[-1]流体出口方向,-1 表示任意
craftEffect特效名完成生产时播放的特效
updateEffect特效名生产过程中偶尔冒的特效
warmupSpeed浮点0.019启动/停机过渡速度
drawer绘制器DrawDefault控制外观,下一节讲

GenericCrafter 在构造器里已经帮你开好了 solidhasItemsupdate 等开关(源码构造器),所以写工厂时这些都不用重复声明。

第一个完整工厂

把前面学的串起来,写一个"强化铜炉":每 2 秒消耗 2 个铜和少量电,产出 1 个上一章做的强化铜。文件 content/blocks/better-copper-furnace.json

hjson
{
  type: GenericCrafter
  name: 强化铜炉
  description: 把普通铜升级成强化铜。
  size: 2
  health: 120
  requirements: [
    copper/60
    lead/30
  ]
  category: crafting
  research: copper-wall

  craftTime: 120
  consumes: {
    power: 0.5
    items: [
      copper/2
    ]
  }
  outputItems: [
    my-first-mod-enriched-copper/1
  ]
}

逐段解释:

  • type: GenericCrafter:声明这是一个工厂方块。
  • name/description:显示名和描述,同上一章,可直接写或放 bundles/
  • size: 2:占 2×2 格,所以需要更大的贴图。
  • requirements: [copper/60, lead/30]:建造材料,用了 item/amount 缩写糖。
  • category: crafting:放进"制造"分类,和原版工厂挤在一起。
  • research: copper-wall:挂在铜墙科技节点下(上一章讲过)。
  • craftTime: 120:2 秒生产一次。
  • consumes: { power: 0.5, items: [copper/2] }:每次生产吃 2 铜 + 0.5 电力。
  • outputItems: [my-first-mod-enriched-copper/1]:产出 1 个你自己的强化铜——注意这里写的是完整内部名my-first-mod-enriched-copper),不是 copper

绘制器:决定方块"长什么样"

最后一个问题:方块怎么画?答案在 drawer 字段上,它接受三种写法(源码 ContentParserDrawBlock 解析):

写法一:字符串(直接点名一个绘制器)

hjson
drawer: DrawDefault

DrawDefault 是最朴素的绘制器:只画方块的主贴图(内部名对应的那张图)。绝大多数简单方块用它就够了,甚至不写 drawer 也默认是它。

写法二:对象(指定类型 + 参数)

hjson
drawer: {
  type: DrawRegion
  suffix: -glow
  rotateSpeed: 2
}

DrawRegion额外画一张后缀贴图:内部名 + suffix,比如这里会找 my-first-mod-better-copper-furnace-glow 这张图。它支持旋转、偏移、变色等一堆参数,常用来给方块加一个转动的风扇或发光的炉心。

写法三:数组(多绘制器叠加 = DrawMulti

hjson
drawer: [
  DrawDefault
  { type: DrawRegion, suffix: -glow, color: "ffd37f" }
]

数组会合成一个 DrawMulti,把里面的绘制器按顺序叠画。这是给方块"叠图层"的标准手段——先画底座,再画会转的部件,再画发光的特效。

贴图命名跟着绘制器走

  • DrawDefault → 用内部名那张图(my-first-mod-方块名.png);
  • DrawRegion + suffix: -glow → 用内部名 + -glow 那张图;
  • 所有贴图仍按上一章的规则,放进 sprites/ 自动加模组名前缀。

效果验证

这一章之后,我们的模组长这样:

my-first-mod/
├─ mod.json
├─ content/
│  ├─ items/enriched-copper.json
│  ├─ liquids/hot-water.json
│  └─ blocks/better-copper-furnace.json
├─ sprites/
│  ├─ enriched-copper.png
│  └─ better-copper-furnace.png
└─ bundles/
   └─ bundle_zh_CN.properties

打包启用后,你应该能在"制造"分类里看到强化铜炉,摆一个,接上电、喂上铜,亲眼看着它每两秒吐出一个强化铜。到这一步,你已经拥有了"定义原料 → 定义产物 → 定义外观"的完整能力。


小结

这一章我们造出了第一个工厂,并理清了方块的三个维度:通性Block 基类的公共字段)、消耗consumes 对象)、外观drawer 绘制器)。记住一个关键变化:v8 的消耗统一走 consumes: {},别再写旧的 consumePower 字段了。

思考题:如果想让强化铜炉"既不耗电、只耗铜",并且外观是"底座 + 一个会转的黄色圆盘",consumesdrawer 分别该怎么写?

下一章,我们走出加工厂,去看两类"向大地要资源"的方块——钻头与泵,以及点亮整个工业帝国的发电机。