5.6 KiB
5.6 KiB
蜂巢意识(Hive Mind)系统设计文档 - v2
1. 需求概述
本设计旨在为 ArachnaeSwarm Mod 实现一个“蜂巢意识”系统。该系统包含两种角色:
- 主节点 (Master):蜂巢的中心。
- 子节点 (Drone):蜂巢的工蜂,可以有多个。
它们之间通过 Hediff(健康状态)进行链接,实现以下核心功能:
- 自动绑定:子节点在生成时,会自动在地图上寻找携带
ARA_HiveMindMasterHediff 的Pawn作为主节点。如果找到多个,则选择第一个进行绑定。如果找不到主节点,子节点会立即死亡。 - 主从死亡联动:当主节点死亡时,所有与之链接的子节点也会立即死亡。
- 链接增益:主节点的力量会随着链接的子节点数量增加而增强。具体表现为主节点的
Hediff严重性(Severity)会随着子节点数量的增加而提升,为后续添加属性加成提供基础。
2. 技术方案
为了实现上述功能,我们将创建以下组件:
2.1. XML 定义 (使用 ARA_ 前缀)
我们将定义两个新的 HediffDef:
HediffDef: ARA_HiveMindMaster- hediffClass:
ArachnaeSwarm.Hediff_HiveMindMaster - 描述: 应用于主节点,用于管理子节点链接并根据数量调整严重性。
- hediffClass:
HediffDef: ARA_HiveMindDrone- hediffClass:
ArachnaeSwarm.Hediff_HiveMindDrone - 描述: 应用于子节点,继承自
HediffWithTarget,其target字段将指向主节点。
- hediffClass:
2.2. C# 类定义 (命名空间: ArachnaeSwarm)
我们将实现两个新的C#类:
-
Hediff_HiveMindMaster- 继承自
Hediff。 - 包含一个
List<Pawn>类型的字段drones,用于存储所有已链接的子节点。 - 提供
RegisterDrone(Pawn drone)和DeregisterDrone(Pawn drone)方法,用于添加和移除子节点。 - 在每次注册/反注册后,更新自身的
Severity属性,其值等于drones.Count。 - 重写
PostRemoved()方法,在主节点死亡或Hediff被移除时,杀死所有已注册的子节点。
- 继承自
-
Hediff_HiveMindDrone- 继承自
HediffWithTarget。 - 重写
PostAdd(DamageInfo? dinfo)方法。在此方法中:- 在当前地图上扫描所有Pawn,查找携带
ARA_HiveMindMasterHediff 的单位。 - 如果找到至少一个,则选择第一个作为
target,并调用其RegisterDrone方法将自己注册进去。 - 如果找不到任何主节点,立即杀死自己 (
pawn.Kill(null, null))。
- 在当前地图上扫描所有Pawn,查找携带
- 重写
PostRemoved()方法,在自身被移除时,如果target仍然有效,则调用其DeregisterDrone方法将自己从中移除。 - 在
PostTick()或类似方法中周期性检查target(主节点)是否已死亡或 Hediff 已被移除。如果是,则立即杀死自己。
- 继承自
3. 开发步骤 (TODO List)
- 步骤 1: 创建 XML 定义
- 在
ArachnaeSwarm/1.6/Defs/HediffDefs/目录下创建ARA_Hediffs_HiveMind.xml文件。
- 在
- 步骤 2: 实现 C# 类
Hediff_HiveMindMaster- 在
ArachnaeSwarm/Source/ArachnaeSwarm/目录下创建Hediff_HiveMindMaster.cs文件并编写代码。
- 在
- 步骤 3: 实现 C# 类
Hediff_HiveMindDrone- 在
ArachnaeSwarm/Source/ArachnaeSwarm/目录下创建Hediff_HiveMindDrone.cs文件并编写代码。
- 在
- 步骤 4: 更新项目文件
- 将新创建的
.cs文件添加到ArachnaeSwarm.csproj项目文件中。
- 将新创建的
- 步骤 5: 编译和测试
- 运行
dotnet build编译项目,修复所有编译错误。 - 进入游戏进行功能测试。
- 运行
4. 参考代码
HediffWithTarget.cs
using Verse;
namespace RimWorld
{
public class HediffWithTarget : HediffWithComps
{
public Thing target;
public override bool ShouldRemove
{
get
{
if (target != null && !(target is Pawn { Dead: not false }))
{
return base.ShouldRemove;
}
return true;
}
}
public override void ExposeData()
{
base.ExposeData();
Scribe_References.Look(ref target, "target");
}
}
}
Hediff_PsychicBond.cs
using Verse;
namespace RimWorld
{
public class Hediff_PsychicBond : HediffWithTarget
{
private const int HediffCheckInterval = 65;
public override string LabelBase => base.LabelBase + " (" + target?.LabelShortCap + ")";
public override bool ShouldRemove
{
get
{
if (!base.ShouldRemove)
{
return pawn.Dead;
}
return true;
}
}
public override void PostRemoved()
{
base.PostRemoved();
Gene_PsychicBonding gene_PsychicBonding = base.pawn.genes?.GetFirstGeneOfType<Gene_PsychicBonding>();
if (gene_PsychicBonding != null)
{
gene_PsychicBonding.RemoveBond();
}
else if (target != null && target is Pawn pawn)
{
pawn.genes?.GetFirstGeneOfType<Gene_PsychicBonding>()?.RemoveBond();
}
}
public override void PostTickInterval(int delta)
{
base.PostTickInterval(delta);
if (pawn.IsHashIntervalTick(65, delta))
{
Severity = (ThoughtWorker_PsychicBondProximity.NearPsychicBondedPerson(pawn, this) ? 0.5f : 1.5f);
}
}
}
}