单位
为什么要塞搬不动海神啊
Mindustry 不仅是一款自动化与塔防游戏,同时也具备**即时战略(RTS)**游戏的要素。在 RTS 游戏中,单位(Unit) 是核心组成部分之一,也是原版中设计复杂度较高的内容类型。本节将简要介绍与单位相关的内容。
创建一个 UnitType
在 Mindustry 中,单位被封装成了mindustry.type.UnitType这一类型。与以往的类型不同的是,其拥有必需的字段constructor,它是用来 创建一个单位实体(Entity) 的提供器(Provider),其取值与所需单位实体的种类有关,见于下表:
new UnitType("tutorial-unit"){{
constructor = UnitEntity::create;
EntityMapping.nameMap.put(name, constructor);
}};UnitType("tutorial-unit").apply{
constructor = UnitEntity::create
EntityMapping.nameMap.put(name, constructor)
}UnitEntity::create:普通飞行单位,如flare、alpha,在 JSON 中用flying表示;MechUnit::create:机甲单位,如mace、crawler、nova,在 JSON 中用mech表示;LegsUnit::create:多足单位,如toxopid、corvus、collaris,在 JSON 中用legs表示;UnitWaterMove::create:海军单位,如risso、sei,在 JSON 中用naval表示;PayloadUnit::create:可载荷单位,如mega、quad、oct,以及埃里克尔的evoke、incite、emanate、quell、disrupt,在 JSON 中用payload表示;TimedKillUnit::create:导弹单位,如创伤的导弹,在 JSON 中用missile表示;TankUnit::create:坦克单位,如stell、vanquish,在 JSON 中用tank表示;ElevationMoveUnit::create:悬浮单位,如elude,在 JSON 中用hover表示;BuildingTetherPayloadUnit::create:建筑绑定单位,如manifold、assemblyDrone,在 JSON 中用tether表示;CrawlUnit::create:爬行单位,如latum、renale。爬虫(crawler)本身是MechUnit,在 JSON 中用crawl表示。
仅设置constructor并不总是足够。UnitType初始化时会检查EntityMapping:若name尚未映射,会自动补到nameMap。但如果constructor指向自定义的Unit实体类,还必须为该类注册classId(例如EntityMapping.register(...)或重写classId()),否则会在校验阶段抛出错误。关于自定义单位实体的详细注册流程,我们将在下一章进行说明。
另一方面,UnitType也存在子类型,但这些子类型主要是在UnitType的基础上预设了部分字段值,并未引入新的功能,属于之前提到的 模板(Template) 类。关于单位的属性,由于所有具体的单位实体均由UnitType统一管理,因此UnitType中的字段既包含了所有单位通用的属性,也包含了仅特定单位实体才会使用的属性。
unit.tutorial-mod-tutorial-unit.name = 演示单位
unit.tutorial-mod-tutorial-unit.description = 不能攻击,但是会被攻击。
unit.tutorial-mod-tutorial-unit.details = 一无所有unit.tutorial-mod-tutorial-unit.name = Tutorial Unit
unit.tutorial-mod-tutorial-unit.description = Incapable of attacking, while capable of being attacked.
unit.tutorial-mod-tutorial-unit.details = Nonetheless关于 UnitType 各字段的含义如下:
envRequired:该单位正常运作所必须全部满足的环境标志;0表示任何环境均可。envEnabled:该单位可以在其中运作的环境标志;只要匹配其中任意一个,单位即可启用。envDisabled:该单位无法在其中运作的环境标志;匹配任意一个时,单位将爆炸或被禁用。speed:移动速度(世界单位/帧)。boostMultiplier:加速时的速度倍率。floorMultiplier:地形对单位移动速度的影响系数。rotateSpeed:机体旋转速度(度/帧)。baseRotateSpeed:机甲基础旋转速度(度/帧)。drag:移动阻力系数。accel:加速度系数。hitSize:单位碰撞箱边长。deathShake:单位死亡时的屏幕抖动强度;-1表示使用默认值。stepShake:足式/机甲单位每步产生的屏幕抖动强度。rippleScale:足式单位产生的涟漪/灰尘效果大小。riseSpeed:单位上升速度系数。fallSpeed:单位不加速时的下落速度系数。missileAccelTime:导弹加速至全速所需的帧数。health:生命值总量。armor:伤害减免值;受到的伤害会减少此数值。range:武器的最小射程;用于接近目标,若设置值大于0则覆盖默认值。maxRange:武器的最大射程。mineRange:单位采矿的范围。buildRange:单位建造的范围。circleTargetRadius:若circleTarget为true,单位环绕目标的半径。crashDamageMultiplier:(飞行单位)撞击敌人时造成的伤害倍率。wreckHealthMultiplier:(飞行单位)残骸生命值相对于最大生命值的倍率。dpsEstimate:单位DPS的粗略估计值;在init()中初始化。clipSize:图形剪裁大小;小于0时自动计算。drownTimeMultiplier:单位溺水速度的倍率;数值越高,溺水越慢。strafePenalty:单位向与其朝向相反的方向移动时的速度惩罚系数。researchCostMultiplier:科技树中研究成本的倍率。groundLayer:(地面单位)绘制所在图层。flyingLayer:(飞行单位)绘制所在图层;若未设置,则根据lowAltitude默认到Layer.flyingUnitLow或Layer.flyingUnit。payloadCapacity:单位的有效载荷容量(世界单位^2)。buildSpeed:建造速度倍率;小于0时禁用建造。aimDst:武器可以瞄准的最小距离;防止单位向自身内部开火。buildBeamOffset:建造光束从前部开始的视觉偏移。mineBeamOffset:采矿光束从前部开始的视觉偏移;默认为碰撞箱边长的一半。targetPriority:目标优先级;低优先级单位总是被忽略,高优先级单位优先被攻击。shadowElevation:(地面单位)阴影绘制的高度偏移;仅影响视觉效果。shadowElevationScl:单位阴影长度的缩放系数;若单位无阴影则无效。engineOffset:引擎从单位中心向后的偏移。engineSize:主引擎半径。engineLayer:所有引擎的绘制图层(小于0时使用默认)。itemOffsetY:单位上物品绘制的视觉向后偏移。lightRadius:单位发出的光照半径;小于0时使用默认。lightOpacity:光照颜色的透明度。softShadowScl:软阴影的缩放系数;其大小基于区域大小计算。fogRadius:战争迷雾视野半径(格);小于0时自动计算。waveTrailX:(海军单位)波浪轨迹的水平偏移。waveTrailY:(海军单位)波浪轨迹的垂直偏移。trailScl:所有轨迹(包括海军)的宽度。isEnemy:若为true,该单位在波次计数器中算作敌人(通常仅用于支援的单位为false)。flying:若为true,单位始终在高度1处(飞行)。wobble:若为true,该飞行单位会摇晃。targetAir:该单位是否尝试攻击空中单位。targetGround:该单位是否尝试攻击地面单位。faceTarget:若为true,单位在射击/瞄准时会尝试面向目标。circleTarget:AI标志;若为true,该飞行单位会像轰炸机一样环绕目标。autoDropBombs:AI标志;若为true,该单位即使不在其“真实”目标旁边也会自动投弹(用于地毯式轰炸机)。targetBuildingsMobile:仅限移动版;若为false,玩家控制时该单位不会自动瞄准建筑进行附着。canBoost:若为true,该单位在玩家/处理器控制时可以加速升空。boostWhenBuilding:若为true,使用建造AI时单位总会加速。boostWhenMining:若为true,使用采矿AI时单位总会加速。logicControllable:若为false,逻辑处理器无法控制该单位。playerControllable:若为false,玩家无法控制该单位。controlSelectGlobal:若为true,该单位可以用全局选择热键(Shift+G)选择。allowedInPayloads:若为false,该单位不能被装入有效载荷。hittable:若为false,该单位不会被子弹或爆炸击中。killable:若为false,该单位不会受到伤害且不能被kill()/destroy()。targetable:若为false,该单位不会被任何东西瞄准。vulnerableWithPayloads:若为true,当单位带有有效载荷时可以被击中/瞄准(假设hittable/targetable为false)。pickupUnits:若为true,该有效载荷单位可以拾取其他单位。physics:若为false,该单位不会与其他单位发生物理碰撞。canDrown:若为true,该地面单位会在深液体中溺水。useUnitCap:若为false,该单位忽略单位上限,可以无限生成。coreUnitDock:若为true,该核心单位会“停靠”到其他单位,使其在“取消停靠”时重新出现。createWreck:若为false,单位死亡时不会创建坠落的“残骸”。createScorch:若为false,单位死亡时不会创建烧焦痕迹。lowAltitude:若为true,该单位会在效果/子弹下方绘制;仅视觉变化。rotateToBuilding:若为true,该单位会看向正在建造的建筑。allowLegStep:若为true且为足式单位,该单位可以跨过方块。legPhysicsLayer:对于足式单位,设为false会强制其处于地面物理层。hovering:若为true,该单位不受其下方地面的影响。omniMovement:若为true,该单位可以朝任何方向移动,无论其朝向如何;若为false,则只能朝其面对的方向移动。rotateMoveFirst:若为true,单位在移动前会先面向移动方向。healFlash:若为true,单位被治疗时会闪烁。canHeal:单位是否可以治疗方块;在init()中初始化。singleTarget:若为true,所有武器攻击同一目标。forceMultiTarget:若为true,即使该单位只有一个镜像武器,也能有多个目标。canAttack:若为false,该单位没有可以攻击的武器。hidden:若为true,该单位不会出现在数据库或各种其他UI中。internal:若为true,该单位仅供内部使用,不会生成贴图。internalGenerateSprites:对于某些单位,即使为内部使用,仍需要生成贴图。bounded:若为false,该单位不会被地图边缘推离。naval:若为true,该单位被检测为海军单位;请勿手动分配,在init()中初始化。autoFindTarget:若为false,RTS AI控制的单位在移动时不会自动攻击目标;此值自动分配。targetUnderBlocks:若为false,不会瞄准“下方”的方块(如传送带)。alwaysShootWhenMoving:若为true,该单位在移动时总会射击,无论减速如何。hoverable:该单位是否有悬停提示。alwaysCreateOutline:若为true,该模组单位总会为其基础生成一个描边区域;通常,如果没有top = false的武器,描边会被忽略。generateFullIcon:仅限原版内容;若为false,跳过完整图标生成步骤。squareShape:若为true,该单位有一个方形阴影。drawBuildBeam:若为true,该单位会绘制其建造光束指向方块。drawMineBeam:若为true,该单位会绘制其采矿光束指向方块。drawCell:若为false,不绘制队伍指示器/格子。drawItems:若为false,不绘制携带的物品。drawShields:若为false,不绘制单位护盾(通常在波次中可见)。drawBody:若为false,不绘制单位主体。drawSoftShadow:若为false,不绘制软阴影。drawMinimap:若为false,不在小地图上绘制该单位。aiController:创建时分配的默认AI控制器。controller:基于单位实体选择AI控制器的函数。constructor:创建该单位类的新实例的提供器。abilities:“能力”列表,这些是每帧更新的各种行为。weapons:该单位将使用的所有武器。immunities:此集合中的状态效果都无法应用于该单位。healColor:该单位被治疗时闪烁的颜色(若healFlash为true)。lightColor:地图中启用光照时该单位产生的光颜色。shieldColor:单位护盾颜色的覆盖;若为null则使用默认。deathSound:该单位爆炸时播放的声音(非被击落时)。deathSoundVolume:死亡声音的音量。wreckSound:单位残骸被击落时播放的声音。wreckSoundVolume:残骸坠落声音的音量。loopSound:该单位在周围时循环播放的声音。loopSoundVolume:循环声音的音量。stepSound:该机甲/昆虫单位踏步时播放的声音。stepSoundVolume:踏步声音的音量。stepSoundPitch:踏步声音的基础音高。stepSoundPitchRange:踏步声音的音高变化范围。tankMoveSound:坦克移动时循环播放的声音。moveSound:单位移动时循环播放的声音;音量取决于速度。moveSoundVolume:移动声音的音量。moveSoundPitchMin:基于速度的移动声音最小音高。moveSoundPitchMax:基于速度的移动声音最大音高。tankMoveVolume:坦克移动音效的音量。fallEffect:该单位坠落时产生的效果。fallEngineEffect:单位坠落时在引擎处创建的效果。deathExplosionEffect:该单位死亡时创建的效果。treadEffect:该坦克移动时可选的效果。parts:额外的(通常是动画的)视觉部件。engines:引擎或“推进器”列表。useEngineElevation:若为false,无论高度如何,推进器总是以其正常大小显示。engineColor:所有引擎颜色的覆盖;若为null则使用默认。engineColorInner:引擎内部部分的颜色。trailLength:引擎轨迹(若飞行)或波浪轨迹(若海军)的长度。trailColor:引擎轨迹颜色的覆盖。flowfieldPathType:流向场/敌人AI寻路的成本类型ID。pathCost:用于计算控制路径查找器移动成本的函数;不影响“正常”的流向场寻路。pathCostId:控制路径查找器中使用的路径成本ID;此值实际有效;请勿手动分配,在init()中设置。sample:该单位类型创建的单位的样本;请勿修改。targetFlags:基于优先级瞄准的标志;null表示应找到最近的目标,最近的敌方核心作为备用目标。allowChangeCommands:值为false用于在单位工厂中隐藏命令更改UI。commands:通过RTS控制该单位可用的命令;空数组意味着命令将根据单位能力在init()中分配。defaultCommand:创建时分配给该单位的命令;null表示数组中的第一个命令。stances:该单位可以拥有的姿态;空数组意味着姿态将根据单位能力在init()中分配。outlineColor:贴图周围生成的描边颜色。outlineRadius:贴图描边的厚度。outlines:若为false,不生成贴图描边。itemCapacity:该单位可以携带的物品数量;小于0时根据碰撞箱大小确定。ammoCapacity:该单位可以持有的弹药量(若启用规则);小于0时根据武器射速确定。ammoType:该单位使用的弹药类型(若启用该系统)。mineTier:该单位可以开采的矿石的最大硬度(小于0时禁用)。mineSpeed:采矿速度(任意单位)。mineWalls:该单位是否可以开采墙壁中的矿石。mineFloor:该单位是否可以开采地板中的矿石。mineHardnessScaling:若为true,较硬的材料需要更长时间开采。mineSound:采矿时持续发出的声音。mineSoundVolume:采矿声音的音量。mineItems:采矿目标物品;用于MinerAI。
对于多足单位:
legCount:该单位的腿数量(必须具有正确的类型才能工作!)。legGroupSize:腿部移动的组大小;例如,昆虫(6条腿)通常以3条为一组移动。legLength:腿的总长度(两个节段)。legSpeed:单条腿向其目的地移动的速度(非线性)。legForwardScl:腿尝试将自身放置在单位前方多远处的比例(相对于单位速度);如果腿落后于单位,增加此数值。legBaseOffset:腿从单位中心的偏移。legMoveSpace:腿部移动间距的缩放。legExtension:对于没有“关节”的腿,这是第二条腿贴图被向后移动的距离,以覆盖关节区域。legPairOffset:此字段的值越高,腿部组之间的移动越不同步。legLengthScl:腿尝试离身体多远的缩放(并非实际长度);例如,若设为0.5,腿会显得有些折叠。legStraightLength:若legStraightness> 0,这是腿离身体水平距离的缩放。legMaxLength:单条腿的最大长度(相对于实际长度的比例)。legMinLength:单条腿的最小长度(相对于实际长度的比例)。legSplashDamage:腿触地时造成的溅射伤害。legSplashRange:腿的溅射伤害范围。baseLegStraightness:腿基部/原点的笔直程度(0 = 圆形,1 = 直线)。legStraightness:腿向外角度的笔直程度(0 = 圆形,1 = 水平线)。legBaseUnder:若为true,基部(较远)的腿部区域绘制在下方而非上方。lockLegBase:若为true,腿被锁定在单位基部,而不是在隐式的旋转“底座”上。legContinuousMove:若为true,即使单位没有移动,腿也总是尝试移动(导致更自然的行为)。flipBackLegs:翻转后腿(TODO:似乎没有太大作用)。flipLegSide:翻转腿侧(TODO:似乎没有太大作用)。emitWalkSound:是否在水中发出溅水声。emitWalkEffect:是否在水中产生溅水效果(若为false则emitWalkSound也为false)。
对于机械单位:
mechLandShake:机甲加速后着陆时的屏幕抖动量。mechSideSway:机甲左右摇摆动画的参数。mechFrontSway:机甲前后摇摆动画的参数。mechStride:机甲步幅。mechStepParticles:若为true,机甲踏步时会产生粒子。mechLegColor:移动时腿的颜色变化,以模拟深度。
对于坦克单位:
treadRects:履带矩形列表,以图像坐标表示,相对于中心,这些矩形会被镜像。treadFrames:履带移动的帧数。treadPullOffset:履带贴图顶部被“切除”的部分相对于图案的比例;这会得到纠正。crushFragile:若为true,“脆弱”的方块会在坦克周围1x1区域内被立即压碎。
对于分节/爬虫单位:
segments:独立节段的数量。segmentUnits:TODO 波次支持 - 对于多单位节段单位,这是生成的独立单位数量。segmentUnit:节段中生成的单位;若为null,则使用相同单位。segmentEndUnit:末端生成的单位;若为null,则使用节段单位。segmentLayerOrder:true- 父节段在较高图层;false- 父节段在头部下方图层。segmentMag:节段之间正弦偏移的幅度。segmentScl:节段之间正弦偏移的缩放。segmentPhase:节段之间正弦偏移的索引倍率。segmentRotSpeed:每个节段向下一个节段移动的速度。segmentMaxRot:节段之间的最大角度差。segmentSpacing:独立单位节段之间的间距(仅用于多单位蠕虫)。segmentRotationRange:节段之间的旋转被限制在此范围内。crawlSlowdown:当crawlSlowdownFrac满足时,该单位的速度倍率。crushDamage:该坦克/爬行单位每帧对下方方块造成的伤害。crawlSlowdownFrac:该单位达到crawlSlowdown所需下方实心方块的比例。
对于导弹单位:
lifetime:该导弹的寿命。homingDelay:导弹开始制导前必须经过的帧数。
为单位添加武器
单位武器是单位实现攻击或修复功能的核心组件,其本质是一个可移动的小型炮塔。与建筑武器不同,单位武器在默认游戏规则下无需消耗弹药即可发射;若启用“单位弹药限制”规则,单位则可以从核心或容器中自动获取所需弹药。武器的主要实现类为Weapon,此外还存在两个专用子类:PointDefenseBulletWeapon用于实现点防御功能,RepairBeamWeapon用于实现修复光束功能。
new UnitType("tutorial-unit"){{
constructor = UnitEntity::create;
weapons.add(new Weapon("tutorial-weapon"){{
bullet = new BasicBulletType(2.5f, 9);
}});
}};UnitType("tutorial-unit").apply{
constructor = UnitEntity::create
weapons.add(Weapon("tutorial-weapon").apply{
bullet = BasicBulletType(2.5f, 9)
})
}关于 Weapon 各字段的含义如下:
name:显示在界面中的武器区域名称;通常用于标识和描述。bullet:发射的子弹类型;定义了子弹的伤害、速度、效果等属性。ejectEffect:射击时弹出的弹壳效果;用于视觉反馈。display:是否在单位的属性统计中显示该武器;true为显示。useAmmo:当游戏规则启用弹药时,是否消耗弹药;true为消耗。mirror:是否在初始化时创建该武器的镜像副本;默认true,用于对称武器。flipSprite:渲染时是否翻转武器贴图;仅限内部使用,请勿手动设置。alternate:当mirror=true时,是否交替射击左右武器;true为交替,false为同时。rotate:武器是否独立于单位旋转以瞄准目标;true为独立旋转。showStatSprite:是否在数据库中显示武器的贴图;true为显示。baseRotation:武器的起始旋转角度(单位:度)。top:是否将描边绘制在顶部;true为顶部,false为底部。continuous:射击时是否将子弹固定在武器上(仍需装填);用于持续激光等。alwaysContinuous:是否使用无需装填的持续射击;隐含continuous=true。aimChangeSpeed:炮塔改变子弹“瞄准”距离的速度;仅用于点激光子弹。controllable:玩家是否可以手动瞄准该武器;true为可以。aiControllable:单位AI是否可以自动瞄准该武器;true为可以。alwaysShooting:无论是否有目标或是否在射击锥形范围内,是否始终射击;true为始终射击。autoTarget:当controllable=false时,是否在update()中自动瞄准相关单位;true为自动瞄准。predictTarget:是否进行目标轨迹预测;true为预测,以提高命中移动目标的能力。useAttackRange:是否将该武器的射程用于单位的攻击范围计算;true为使用。targetInterval:切换目标前等待的帧数;用于控制目标切换频率。targetSwitchInterval:目标切换间隔的帧数;与targetInterval类似,但可能用于不同场景。rotateSpeed:武器旋转速度(单位:度/帧);仅当rotate=true时有效。reload:武器装填时间(单位:帧);两次射击之间的间隔。inaccuracy:每次射击的角度不准确度(单位:度);值越高,弹道越分散。shake:每次射击的屏幕抖动强度和持续时间;用于增强射击反馈。recoil:视觉上的武器后坐力;影响武器射击后的后退距离。recoils:后坐力的额外计数器数量;-1表示使用默认值。recoilTime:武器返回起始位置所需时间(单位:帧);默认使用装填时间。recoilPow:应用于视觉后坐力的功率曲线;影响后坐力的变化方式。cooldownTime:热区域冷却所需帧数;用于显示武器过热效果。shootX:子弹/效果从武器中心出发的X轴偏移。shootY:子弹/效果从武器中心出发的Y轴偏移。x:武器在单位上的X轴位置偏移。y:武器在单位上的Y轴位置偏移。xRand:X轴随机散布;增加射击的随机性。yRand:Y轴随机散布;增加射击的随机性。shoot:子弹的发射模式;定义了子弹的发射角度、数量等。shadow:武器下方阴影的半径;小于0时禁用阴影。velocityRnd:子弹速度的随机分数;增加速度的随机性。extraVelocity:额外速度分数;在基础速度上增加的速度比例。shootCone:开始射击的锥形半角(单位:度);目标在此锥形内才会开火。rotationLimit:武器相对于其底座可以旋转的角度范围(单位:度)。minWarmup:开火前的最小预热阈值(非线性);用于控制开火前的准备。shootWarmupSpeed:射击预热速度的插值速度;仅用于部件。smoothReloadSpeed:平滑装填速度的插值速度;用于装填动画。linearWarmup:射击预热是否为线性;true为线性,false为曲线。soundPitchMin:射击声音的最小音高。soundPitchMax:射击声音的最大音高。ignoreRotation:射击时是否忽略射击者的旋转;true为忽略。noAttack:该武器是否不能用于攻击目标;true为不能攻击。minShootVelocity:射击所需的最小速度;低于此速度不会射击。parentizeEffects:射击效果是否跟随单位(效果需设置followParent=true);true为跟随。otherSide:用于交替射击的内部值;请勿更改。layerOffset:相对于默认值的绘制Z轴偏移;用于调整绘制层级。activeSound:射击时循环播放的声音;用于持续射击武器。activeSoundVolume:活动声音的音量。shootSound:射击时播放的声音。shootSoundVolume:射击声音的音量。initialShootSound:首次开火时播放的声音(仅用于持续武器)。chargeSound:武器充能时播放的声音(用于有延迟的武器)。region:显示的武器贴图区域(自动加载)。heatRegion:热区域贴图,必须与region大小相同(可选)。cellRegion:单元格区域贴图,必须与region大小相同(可选)。outlineRegion:当top=false时显示的描边区域。heatColor:热区域着色颜色;用于显示武器过热效果。shootStatus:射击时施加的状态效果;如燃烧、减速等。mountType:要使用的武器底座类型;通过函数提供武器底座实例。shootStatusDuration:射击时施加状态效果的持续时间(单位:帧)。shootOnDeath:所有者死亡时是否触发射击;true为触发。parts:额外的动画部件;用于增强武器的视觉效果。和DrawTurret一样,也是DrawPart。
单位的贴图
贴图是模组最重要的外在特征之一,其实现细节会随着深入理解而逐渐显现。本部分将简要介绍单位实际所需的全部贴图,其内在逻辑将在后续章节详细说明。
单位的基本贴图包括本体贴图tutorial-unit.png和队伍色贴图tutorial-unit-cell.png。本体贴图在绘制时位于最底层。队伍色贴图用于指示单位的所属队伍,其颜色闪烁速度与单位生命值相关。该贴图使用#ffffff、#dcc6c6、#9d7f7f三种颜色分别标记队伍颜色中的亮部、中部和暗部区域,使用其他颜色将导致该区域被原样绘制。此外,游戏会自动为所有单位贴图应用**描边(Outline)和线性图像滤波(Linear Image Filter)**处理,以使图像边界更清晰、显示更平滑。这两项处理的具体原理将在后续章节说明。在当前版本中,该过程为全自动执行,通常无需干预,也无须额外提供描边贴图。
仅有上述两种贴图可能不足以满足所有显示需求。例如,在核心数据库和建造栏中,单位图标若仅使用本体贴图,其视觉效果可能与原版单位存在差异。原版单位在这些界面中通常使用完整预览贴图tutorial-unit-full.png。在绘制完整预览贴图时,应呈现单位组装完成后的最终外观,包括所有武器(含描边效果)和队伍色区域。但最外层的最终描边应由游戏自动处理,且无需绘制LegsUnit的全部腿部细节或单位的推进器效果。
武器贴图的处理原则类似。武器本体贴图tutorial-weapon.png是必需的,但尺寸较小的武器可以不提供队伍色贴图。武器还可以拥有过热效果贴图tutorial-weapon-heat.png,该贴图仅能使用不同透明度的#ffffff白色,通常经过高斯模糊处理以达到最佳视觉效果。此外,可通过预览贴图tutorial-weapon-preview.png来设置在核心数据库中显示的武器图标。
对于LegsUnit(多足单位),还需准备以下贴图:joint-base(近身关节)、leg(腿部)、joint(腿部关节)和foot(足部)。对于TankUnit(坦克单位),需要准备履带贴图。自版本 v151 起,通常只需提供一张-tread贴图,游戏即可自动生成内部所需的其他相关贴图。
单位的能力
单位的能力(Ability)是独立于战斗系统的一套使单位发挥作用的系统,在 Mindustry 中,能力系统常与战斗系统结合使用。它可以控制单位的行为和绘制,也可以在单位出生或死亡时执行特定操作。
原版中的 Ability 如下:
ArmorPlateAbility:装甲板能力,在射击时减少受到的伤害;EnergyFieldAbility:能量场能力,对附近的敌人释放电击,或治疗友方,如“玄武”;ForceFieldAbility:力墙场能力,投射一个能吸收子弹的力场护盾,如“耀星”;LiquidExplodeAbility:死亡溢液能力,死亡时释放液体,如 Latum;LiquidRegenAbility:液体吸收能力,吸收液体以治疗自身,如 Latum;MoveEffectAbility:移动特效能力,边移动边产生特效,如创伤导弹;MoveLightningAbility:闪电助推器能力,移动时释放闪电,如 v5 中的 Dart;RegenAbility:再生能力,随着时间的推移恢复自己的生命值,如“耀星”;RepairFieldAbility:修复场能力,修复附近的单位,如“新星”;ShieldArcAbility:弧形护盾能力,投射一个弧形的力场护盾,能吸收子弹,如“天理”;SpawnDeathAbility:死亡产生单位能力,死亡时释放单位,如 Latum;StatusFieldAbility:状态场能力,对附近的单位施加状态效果,如电鳗;SuppressionFieldAbility:修复压制场能力,使附近的修复建筑停止工作,如“龙王”;UnitSpawnAbility:单位生成能力,建造单位,如“海神”。
单位命令与姿态
单位命令(UnitCommand)与姿态(UnitStance)是 v8 中新添加的两种内容类型,应用于 RTS 系统。单位命令可以更换单位的 AI。单位姿态给单位标记状态(State),本身没有功能,只是供单位 AI 读取并作出反应。由于与 AI 的强耦合性,现阶段没有必要注册新的单位命令和姿态。
单位支持的姿态和命令既可以手动指定,也可以让游戏根据单位本身的参数自动添加。
关于单位采矿菜单中缺少模组矿物的问题,可通过注册新的ItemUnitStance并将其添加至单位姿态列表来解决:
ItemUnitStance item1mine = new ItemUnitStance(ModItems.item1);
UnitTypes.mono.stances.add(item1mine);
//省略若干单位单位 AI
单位 AI 是控制单位行为的逻辑系统,当单位处于非玩家队伍或无玩家控制时,由 AI 接管其决策与行动。玩家队伍的单位则由CommandAI管理,其行为受单位指令系统调控。
原版中的 AI 存放于mindustry.ai.types包内,包含以下几种类型。部分 AI 的使用需要满足特定条件:
- GroundAI:地面单位 AI,用于控制地面移动的单位,如尖刀、战锤等
- FlyingAI:飞行单位 AI,用于控制飞行单位,如星辉、天垠等
- MinerAI:采矿 AI,用于控制采矿单位,如独影等
- BuilderAI:建造 AI,用于控制建造单位,如幻型、阿尔法等
- SuicideAI:自杀式攻击 AI,用于控制自爆单位,如爬虫等
- MissileAI:导弹 AI,用于控制导弹单位,如创伤的导弹
- FlyingFollowAI:跟随型飞行 AI,常见于需要跟随目标的飞行单位
- BoostAI:助推飞行 AI,用于可升空单位的起降逻辑
- RepairAI:修复 AI,用于靠近并修复友方单位/建筑
- DefenderAI:防御 AI,用于以防守为主的单位
- CargoAI:运输 AI,用于物流单位的运输任务
- PrebuildAI:预建 AI,用于处理预建任务的单位
- AssemblerAI:组装 AI,用于单位组装厂的装配无人机
- HugAI:贴身 AI,用于近身黏附型单位(如
latum、renale) - LogicAI:逻辑 AI,用于逻辑控制的单位
- CommandAI:指挥 AI,用于玩家队伍的单位指令系统
在给单位的aiController字段赋值时,需要提供一个Prov类型的值,例如GroundAI::new。controller用于根据队伍与可控性选择 AI(默认玩家队伍使用CommandAI,AI 队伍使用aiController),因此一般不建议直接替换controller,除非你同时处理玩家/AI 的分支逻辑。
单位工厂与重构厂
原版中与单位配套的重要建筑是单位工厂和单位重构厂,以及埃里克尔中使用的单位组装厂。
单位工厂类型是mindustry.world.blocks.units.UnitFactory,它继承自mindustry.world.blocks.units.UnitBlock(而UnitBlock又继承自mindustry.world.blocks.payloads.PayloadBlock)。PayloadBlock是所有载荷方块的基类,定义了载荷移动速度payloadSpeed和载荷转弯速度payloadRotateSpeed两个属性,并要求加载-top、-out、-in三张贴图。
单位工厂的主要设置项是其plans字段,这个字段接收一个包含UnitPlan的Seq。UnitPlan的构造接受三个参数,分别为制造单位、生产时间和物品消耗。
groundFactory = new UnitFactory("ground-factory"){{
requirements(Category.units, with(Items.copper, 50, Items.lead, 120, Items.silicon, 80));
plans = Seq.with(
new UnitPlan(UnitTypes.dagger, 60f * 15, with(Items.silicon, 10, Items.lead, 10)),
new UnitPlan(UnitTypes.crawler, 60f * 10, with(Items.silicon, 8, Items.coal, 10)),
new UnitPlan(UnitTypes.nova, 60f * 40, with(Items.silicon, 30, Items.lead, 20, Items.titanium, 20))
);
size = 3;
consumePower(1.2f);
researchCostMultiplier = 0.5f;
}};val groundFactory = UnitFactory("ground-factory").apply {
requirements(Category.units, with(Items.copper, 50, Items.lead, 120, Items.silicon, 80))
plans = Seq.with(
UnitPlan(UnitTypes.dagger, 60f * 15, with(Items.silicon, 10, Items.lead, 10)),
UnitPlan(UnitTypes.crawler, 60f * 10, with(Items.silicon, 8, Items.coal, 10)),
UnitPlan(UnitTypes.nova, 60f * 40, with(Items.silicon, 30, Items.lead, 20, Items.titanium, 20))
)
size = 3
consumePower(1.2f)
researchCostMultiplier = 0.5f
}单位重构厂的类型为mindustry.world.blocks.units.Reconstructor。在 Mindustry 中,单位重构厂的消耗通过消耗器系统实现,其重构时间由constructTime字段控制,单位的升级路径则由upgrades字段定义。
tetrativeReconstructor = new Reconstructor("tetrative-reconstructor"){{
requirements(Category.units, with(Items.lead, 4000, Items.silicon, 3000, Items.thorium, 1000, Items.plastanium, 600, Items.phaseFabric, 600, Items.surgeAlloy, 800));
size = 9;
consumePower(25f);
consumeItems(with(Items.silicon, 1000, Items.plastanium, 600, Items.surgeAlloy, 500, Items.phaseFabric, 350));
consumeLiquid(Liquids.cryofluid, 3f);
constructTime = 60f * 60f * 4;
createSound = Sounds.unitCreateBig;
upgrades.addAll(
new UnitType[]{UnitTypes.antumbra, UnitTypes.eclipse},
new UnitType[]{UnitTypes.arkyid, UnitTypes.toxopid},
new UnitType[]{UnitTypes.scepter, UnitTypes.reign},
new UnitType[]{UnitTypes.sei, UnitTypes.omura},
new UnitType[]{UnitTypes.quad, UnitTypes.oct},
new UnitType[]{UnitTypes.vela, UnitTypes.corvus},
new UnitType[]{UnitTypes.aegires, UnitTypes.navanax}
);
}};val tetrativeReconstructor = Reconstructor("tetrative-reconstructor").apply {
requirements(Category.units, with(Items.lead, 4000, Items.silicon, 3000, Items.thorium, 1000, Items.plastanium, 600, Items.phaseFabric, 600, Items.surgeAlloy, 800))
size = 9
consumePower(25f)
consumeItems(with(Items.silicon, 1000, Items.plastanium, 600, Items.surgeAlloy, 500, Items.phaseFabric, 350))
consumeLiquid(Liquids.cryofluid, 3f)
constructTime = 60f * 60f * 4
createSound = Sounds.unitCreateBig
upgrades.addAll(
arrayOf(UnitTypes.antumbra, UnitTypes.eclipse),
arrayOf(UnitTypes.arkyid, UnitTypes.toxopid),
arrayOf(UnitTypes.scepter, UnitTypes.reign),
arrayOf(UnitTypes.sei, UnitTypes.omura),
arrayOf(UnitTypes.quad, UnitTypes.oct),
arrayOf(UnitTypes.vela, UnitTypes.corvus),
arrayOf(UnitTypes.aegires, UnitTypes.navanax)
)
}单位组装厂的类型为mindustry.world.blocks.units.UnitAssembler。该类型会生成若干无人机作为组装的先决条件,随后接收配方要求的载荷/物品/液体输入,并在指定区域内生成新的单位。与其他载荷方块不同,此类型将载荷视为可消耗物资,并统一纳入消耗器系统进行管理。可设置的参数包括无人机单位类型droneType、无人机数量dronesCreated以及制造无人机所需时间droneConstructTime。其配方plans的设置方式与前述类型相似。配方的序号对应模块等级:第一个配方无需模块,第二个配方需要至少一个tier=1模块,第三个配方需要tier=1与tier=2连续覆盖,以此类推:
tankAssembler = new UnitAssembler("tank-assembler"){{
requirements(Category.units, with(Items.thorium, 500, Items.oxide, 150, Items.carbide, 80, Items.silicon, 650));
regionSuffix = "-dark";
size = 5;
plans.add(
new AssemblerUnitPlan(UnitTypes.vanquish, 60f * 50f, PayloadStack.list(UnitTypes.stell, 4, Blocks.tungstenWallLarge, 10)),
new AssemblerUnitPlan(UnitTypes.conquer, 60f * 60f * 3f, PayloadStack.list(UnitTypes.locus, 6, Blocks.carbideWallLarge, 20))
);
areaSize = 13;
researchCostMultiplier = 0.4f;
consumePower(2.5f);
consumeLiquid(Liquids.cyanogen, 9f / 60f);
}};val tankAssembler = UnitAssembler("tank-assembler").apply {
requirements(Category.units, with(Items.thorium, 500, Items.oxide, 150, Items.carbide, 80, Items.silicon, 650))
regionSuffix = "-dark"
size = 5
plans.add(
AssemblerUnitPlan(UnitTypes.vanquish, 60f * 50f, PayloadStack.list(UnitTypes.stell, 4, Blocks.tungstenWallLarge, 10)),
AssemblerUnitPlan(UnitTypes.conquer, 60f * 60f * 3f, PayloadStack.list(UnitTypes.locus, 6, Blocks.carbideWallLarge, 20))
)
areaSize = 13
researchCostMultiplier = 0.4f
consumePower(2.5f)
consumeLiquid(Liquids.cyanogen, 9f / 60f)
}