在RimWorld的Mod开发中,太阳能发电机是最基础但也最具改造潜力的建筑之一。许多Modder止步于复刻原版功能,却忽略了它作为电力系统核心组件的扩展可能性。本文将带你突破常规,通过两个实战功能改造——储能模块与天气影响系统,掌握如何让基础建筑焕发新生。
原版太阳能发电机最大的局限就是夜间完全断电。我们可以通过添加简易电池功能来解决这个问题,让白天多余的电量储存起来供夜晚使用。
首先需要在Building类中新增储能相关字段:
csharp复制public class Building_AdvancedSolarGenerator : Building
{
private const float FullSunPower = 1700f;
private const float NightPower = 0f;
private float _batteryCapacity = 500f; // 最大储能
private float _currentStorage; // 当前储能
private float _dischargeRate = 100f; // 夜间放电速率
private bool _isDaytime => Map.skyManager.CurSkyGlow > 0.35f;
// 其余现有字段...
}
修改Tick()方法实现充放电逻辑:
csharp复制public override void Tick()
{
base.Tick();
float powerOutput;
if (_isDaytime)
{
// 白天:发电并充电
float generatedPower = (FullSunPower - NightPower) * Map.skyManager.CurSkyGlow * RoofedFactor;
float excessPower = generatedPower - compPowerTrader.PowerOutput;
if (excessPower > 0)
{
_currentStorage = Mathf.Min(_currentStorage + excessPower * 0.8f, _batteryCapacity);
}
powerOutput = generatedPower;
}
else
{
// 夜晚:放电
if (_currentStorage > 0)
{
powerOutput = Mathf.Min(_dischargeRate, _currentStorage);
_currentStorage -= powerOutput;
}
else
{
powerOutput = 0;
}
}
compPowerTrader.PowerOutput = powerOutput;
}
在Draw()方法中添加储能状态显示:
csharp复制public override void Draw()
{
base.Draw();
// 原有电量条绘制代码...
// 添加储能条
if (_batteryCapacity > 0)
{
var storageBarPos = DrawPos + Vector3.up * 0.25f;
var storageFillPercent = _currentStorage / _batteryCapacity;
GenDraw.FillableBarRequest storageBar = new()
{
center = storageBarPos,
size = new Vector2(1.8f, 0.08f),
fillPercent = storageFillPercent,
filledMat = SolidColorMaterials.SimpleSolidColorMaterial(new Color(0.2f, 0.6f, 0.8f)),
unfilledMat = SolidColorMaterials.SimpleSolidColorMaterial(new Color(0.1f, 0.1f, 0.1f)),
margin = 0.1f,
rotation = Rotation
};
GenDraw.DrawFillableBar(storageBar);
}
}
原版仅考虑天空亮度和屋顶遮挡,我们可以扩展更细致的天气影响。
首先定义不同天气类型的影响系数:
| 天气类型 | 效率系数 | 额外说明 |
|---|---|---|
| 晴天 | 1.0 | 基准值 |
| 薄雾 | 0.85 | 轻微影响 |
| 雨天 | 0.65 | 中度影响 |
| 暴雨 | 0.5 | 重度影响 |
| 雪天 | 0.7 | 积雪反射可能提升效率 |
| 沙尘暴 | 0.4 | 极端影响 |
添加天气检测方法和字段:
csharp复制private float GetWeatherEfficiency()
{
if (Map.weatherManager.IsRainOrSnow)
{
if (Map.weatherManager.RainRate > 0.7f)
return 0.5f; // 暴雨
return 0.65f; // 普通雨天
}
if (Map.weatherManager.IsFoggy)
return 0.85f;
if (Map.weatherManager.IsSnowing)
return 0.7f;
if (Map.weatherManager.IsSandstorm)
return 0.4f;
return 1f; // 晴天
}
修改realPower属性:
csharp复制private float realPower =>
(FullSunPower - NightPower) *
Map.skyManager.CurSkyGlow *
RoofedFactor *
GetWeatherEfficiency();
好的Mod应该允许玩家调整参数。我们可以通过XML定义这些值:
xml复制<comps>
<li Class="CompProperties_Power">
<compClass>CompPowerTrader</compClass>
<basePowerConsumption>1</basePowerConsumption>
<transmitsPower>true</transmitsPower>
</li>
<li Class="CompProperties_SolarAdvanced">
<maxBatteryCapacity>750</maxBatteryCapacity>
<dischargeRate>150</dischargeRate>
<weatherImpactEnabled>true</weatherImpactEnabled>
</li>
</comps>
对应的属性组件类:
csharp复制public class CompProperties_SolarAdvanced : CompProperties
{
public float maxBatteryCapacity = 500f;
public float dischargeRate = 100f;
public bool weatherImpactEnabled = true;
public CompProperties_SolarAdvanced()
{
compClass = typeof(CompSolarAdvanced);
}
}
更真实的模拟可以考虑地理位置:
csharp复制private float GetLatitudeEfficiency()
{
float latitude = Mathf.Abs(Find.WorldGrid.LongLatOf(Map.Tile).y);
return Mathf.Lerp(0.8f, 1.2f, 1 - latitude / 90f);
}
通过研究解锁效率提升:
csharp复制private float GetResearchBonus()
{
float bonus = 0f;
if (ResearchProjectDefOf.SolarPanels.IsFinished)
bonus += 0.1f;
if (ModsConfig.IsActive("MyMod.AdvancedSolar"))
bonus += 0.15f;
return 1 + bonus;
}
整合所有因素后的最终发电公式:
csharp复制private float realPower =>
(FullSunPower - NightPower) *
Map.skyManager.CurSkyGlow *
RoofedFactor *
GetWeatherEfficiency() *
GetLatitudeEfficiency() *
GetResearchBonus();
在实际项目中,这种模块化设计让后续添加新功能变得非常简单。比如要添加清洁度影响,只需新增一个GetCleanlinessFactor()方法并在公式中相乘即可。