Skip to content

Commit 0677f4e

Browse files
committed
新增建筑文档,详细说明建筑配置、存储和电力设置等内容
1 parent 938a1e8 commit 0677f4e

1 file changed

Lines changed: 196 additions & 0 deletions

File tree

content/buildings.md

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# 新增建筑
2+
3+
这一章做一个真正会出现在建造菜单里的建筑。建筑和普通物品不一样,它要处理占格、材料、建造时间、电力、端口、储存、逻辑信号等内容,所以代码通常会拆成两部分:
4+
5+
- `IBuildingConfig`:告诉游戏这个建筑长什么样、占几格、需要什么材料。
6+
- Harmony Patch:把建筑放进建造菜单,并解锁到某个科技里。
7+
8+
下面的写法参考了 `NOIMods/AutomaticHarvest`,但会删掉自动收获器自己的业务逻辑,只保留新增建筑最常用的骨架。
9+
10+
## 文件结构
11+
12+
```text
13+
MyFirstBuilding/
14+
├── MyFirstBuildingConfig.cs
15+
├── Patches.cs
16+
└── STRINGS.cs
17+
```
18+
19+
`MyFirstBuildingConfig.cs` 管建筑本体,`Patches.cs` 负责注册入口,`STRINGS.cs` 放名称和描述。
20+
21+
## 建筑配置
22+
23+
新增建筑需要继承 `IBuildingConfig`。最少要实现三个阶段:
24+
25+
- `CreateBuildingDef()`:定义尺寸、动画、材料、建造规则。
26+
- `ConfigureBuildingTemplate()`:给建筑预制体加组件。
27+
- `DoPostConfigureComplete()`:在建筑完成配置后补运行组件。
28+
29+
```csharp
30+
using TUNING;
31+
using UnityEngine;
32+
33+
namespace MyFirstBuilding
34+
{
35+
public class MyFirstBuildingConfig : IBuildingConfig
36+
{
37+
public const string ID = "MyFirstBuilding";
38+
39+
public override BuildingDef CreateBuildingDef()
40+
{
41+
BuildingDef def = BuildingTemplates.CreateBuildingDef(
42+
ID,
43+
1,
44+
1,
45+
"my_first_building_kanim",
46+
30,
47+
60f,
48+
BUILDINGS.CONSTRUCTION_MASS_KG.TIER2,
49+
MATERIALS.REFINED_METALS,
50+
1600f,
51+
BuildLocationRule.OnFloor,
52+
DECOR.NONE,
53+
NOISE_POLLUTION.NONE
54+
);
55+
56+
def.Floodable = false;
57+
def.Entombable = true;
58+
def.Overheatable = false;
59+
def.AudioCategory = "Metal";
60+
def.DefaultAnimState = "off";
61+
def.ObjectLayer = ObjectLayer.Building;
62+
63+
return def;
64+
}
65+
66+
public override void ConfigureBuildingTemplate(GameObject go, Tag prefabTag)
67+
{
68+
go.AddOrGet<Operational>();
69+
go.AddOrGet<CopyBuildingSettings>();
70+
}
71+
72+
public override void DoPostConfigureComplete(GameObject go)
73+
{
74+
go.AddOrGet<LogicOperationalController>();
75+
}
76+
}
77+
}
78+
```
79+
80+
先不要急着往里面塞功能。建筑能被注册、能建出来、能正常保存读取以后,再加自己的组件会稳很多。
81+
82+
## 加储存
83+
84+
如果建筑需要存东西,直接加 `Storage`
85+
86+
```csharp
87+
public override void ConfigureBuildingTemplate(GameObject go, Tag prefabTag)
88+
{
89+
Storage storage = go.AddOrGet<Storage>();
90+
storage.capacityKg = 1000f;
91+
storage.storageFilters = STORAGEFILTERS.SOLIDS;
92+
storage.showCapacityStatusItem = true;
93+
storage.showCapacityAsMainStatus = true;
94+
95+
storage.SetDefaultStoredItemModifiers(new[]
96+
{
97+
Storage.StoredItemModifier.Preserve
98+
});
99+
}
100+
```
101+
102+
`capacityKg` 是容量,`storageFilters` 是允许放入的标签。比如只收种子可以用 `GameTags.Seed`,只收食物可以用 `GameTags.Edible`
103+
104+
## 加电力
105+
106+
建筑需要耗电时,在 `CreateBuildingDef()` 里打开电力输入:
107+
108+
```csharp
109+
def.RequiresPowerInput = true;
110+
def.EnergyConsumptionWhenActive = 120f;
111+
def.SelfHeatKilowattsWhenActive = 1f;
112+
def.PowerInputOffset = new CellOffset(0, 0);
113+
```
114+
115+
然后在 `DoPostConfigureComplete()` 里补 `EnergyConsumer`
116+
117+
```csharp
118+
public override void DoPostConfigureComplete(GameObject go)
119+
{
120+
go.AddOrGet<Operational>();
121+
go.AddOrGet<EnergyConsumer>();
122+
}
123+
```
124+
125+
如果忘了 `EnergyConsumer`,建筑可能显示有电力口,但运行状态不对。
126+
127+
## 放进建造菜单
128+
129+
建筑配置写好以后,还需要告诉游戏:把它放到哪个分类里。
130+
131+
```csharp
132+
using HarmonyLib;
133+
134+
namespace MyFirstBuilding
135+
{
136+
public static class Patches
137+
{
138+
[HarmonyPatch(typeof(GeneratedBuildings), "LoadGeneratedBuildings")]
139+
public static class GeneratedBuildings_LoadGeneratedBuildings_Patch
140+
{
141+
public static void Prefix()
142+
{
143+
ModUtil.AddBuildingToPlanScreen("Base", MyFirstBuildingConfig.ID);
144+
}
145+
}
146+
147+
[HarmonyPatch(typeof(Db), "Initialize")]
148+
public static class Db_Initialize_Patch
149+
{
150+
public static void Postfix()
151+
{
152+
Db.Get().Techs.Get("BasicRefinement")
153+
.unlockedItemIDs
154+
.Add(MyFirstBuildingConfig.ID);
155+
}
156+
}
157+
}
158+
}
159+
```
160+
161+
`"Base"` 是建造菜单分类,`"BasicRefinement"` 是科技 ID。想放到别的分类或科技里,可以先找一个原版建筑,看看它所在的分类和解锁科技,再照着填。
162+
163+
## 本地化文本
164+
165+
建筑菜单需要名称、描述和效果:
166+
167+
```csharp
168+
namespace MyFirstBuilding
169+
{
170+
public static class STRINGS
171+
{
172+
public static class BUILDINGS
173+
{
174+
public static class PREFABS
175+
{
176+
public static class MYFIRSTBUILDING
177+
{
178+
public static LocString NAME = "我的第一个建筑";
179+
public static LocString DESC = "一个用于测试建筑注册流程的小建筑。";
180+
public static LocString EFFECT = "可以建造、选择,并接入后续自定义逻辑。";
181+
}
182+
}
183+
}
184+
}
185+
}
186+
```
187+
188+
注意类名通常使用大写 ID。也就是说 `MyFirstBuildingConfig.ID = "MyFirstBuilding"` 时,文本路径一般是 `STRINGS.BUILDINGS.PREFABS.MYFIRSTBUILDING`
189+
190+
## 常见问题
191+
192+
建筑出现在菜单但不能建,多半是材料分类或科技解锁写错了。先把材料改成 `MATERIALS.ALL_METALS``MATERIALS.RAW_MINERALS` 测试。
193+
194+
建筑建出来后状态很怪,检查 `Operational``EnergyConsumer``Storage` 这些组件是不是放在了正确阶段。
195+
196+
动画不显示,先确认 `.anim``.build``.png` 都打进 `anim/assets`,并且 `Assets.GetAnim()` 使用的是 `xxx_kanim`

0 commit comments

Comments
 (0)