Skip to content
天气、季节与环境温度 · 英文 Wiki 归档经源码复核后整理

时序、天气与季节 ​

天空不是一成不变的背景板——它会下雨、起雾、打雷,四季会让白昼变长或缩短,温度会让水面结冰又融化。理解这套动态天气与季节系统,你将能预判危险、规划农耕周期、在暴风雪中提前找到庇护所。

整理来源

本页参考根目录英文 Wiki 归档中的 Weather.md、Seasons.md,并用当前源码的 SubsystemWeather、SubsystemSeasons、WorldSettings 和中文语言文件复核。英文 Wiki 中无法由源码确认的旧版本数值与存档修改技巧没有搬入正文。

时间基础 ​

在讨论天气和季节之前,你需要先理解游戏内的时间单位——这是所有周期性现象的基础节拍器。

游戏内时间换算 ​

游戏引擎将一天定义为 1200 个游戏时间单位。在默认时间倍率下,1 游戏时间单位 ≈ 1 现实秒,因此:

一天=1200 游戏时间单位≈20 现实分钟\text{一天} = 1200\ \text{游戏时间单位} \approx 20\ \text{现实分钟}

一年=年天数×1200 游戏时间单位,默认年天数=24\text{一年} = \text{年天数} \times 1200\ \text{游戏时间单位},\quad \text{默认年天数}=24

一个季节=一年4=6 天\text{一个季节} = \frac{\text{一年}}{4} = 6\ \text{天}

概念游戏内时长现实时长
一天1200 时间单位20 分钟
一年24 天8 小时
一个季节6 天2 小时
一季节内阶段2 天40 分钟

注意:1200 是引擎内部的"一天的周期总量",它是一个周期数值而非游戏内显示的秒数。引擎通过 TimeOfDay = Day mod 1(即当前天数的余数部分)来计算一天中的时刻(0~1),再根据该数值划分黎明、白天、黄昏、黑夜四个区间。游戏内时钟界面的"16小时制"是面向玩家的显示换算,与引擎底层的 1200 周期数值是两套系统,不应混用。

其中:年天数是玩家在创建世界时可调的参数(默认24),数值越大则季节更替越缓慢。

昼夜阶段 ​

一天被划分为四个阶段:

阶段含义
黎明 Dawn天刚亮,光线逐渐变强
白天 Day完全天亮,太阳高照
黄昏 Dusk太阳下山,光线逐渐变暗
黑夜 Night完全天黑,需光源照明

季节系统 ​

四季不仅改变景色,更深刻影响着温度、降水频率、昼夜长短和生存难度。掌握季节规律是中长期生存规划的必修课。

四季划分 ​

季节机制将一年( T 0~1)均分为四等份:

季节={夏季若 T∈[0.00, 0.25]秋季若 T∈[0.25, 0.50]冬季若 T∈[0.50, 0.75]春季若 T∈[0.75, 1.00]\text{季节} = \begin{cases} \text{夏季} & \text{若}\ \text{T} \in [0.00,\ 0.25] \\ \text{秋季} & \text{若}\ \text{T} \in [0.25,\ 0.50] \\ \text{冬季} & \text{若}\ \text{T} \in [0.50,\ 0.75] \\ \text{春季} & \text{若}\ \text{T} \in [0.75,\ 1.00] \end{cases}

其中:T为当前年份进度(0=年初夏开始,0.5=初冬,1=回到年初夏)。默认情况下每个季节持续6游戏天。

季节温度修正 ​

季节对温度的修正机制将一年中的时间点映射为温度修正值,呈对称的"V"形:

季节修正=曲线(T),T∈[0, 1]\text{季节修正} = \text{曲线}\big(\text{T}\big),\quad \text{T} \in [0,\ 1]

其中:曲线为分段线性插值曲线;T为当前年份进度。关键节点如下:

季节阶段温度修正通俗解释
盛夏0无修正,最温暖
初秋0气温尚未明显下降
中秋-4开始变冷
初冬-12明显寒冷
隆冬-24全年最冷,温度暴跌
初春-12仍较寒冷
仲春-4开始回暖

隆冬时节温度修正为-24,这意味着一个原本温度10的温带区域,在冬季会变成10-24=-14,远低于冰点,整片区域会被冰雪覆盖。而同一区域在夏季温度是10,完全不会结冰。季节让世界的面貌在一年内发生剧变。

季节对昼夜长短的影响 ​

昼长不是固定的——夏季白天长,冬季白天短。以下是计算昼长的公式:

昼长=lerp(0.2, 0.4, 0.5+0.5×cos⁡(2π×距夏至偏移))\text{昼长} = \mathrm{lerp}\big(0.2,\ 0.4,\ 0.5 + 0.5 \times \cos(2\pi \times \text{距夏至偏移})\big)

黎明+黄昏=0.4 (固定)\text{黎明+黄昏} = 0.4\ \text{(固定)}

黑夜=1−昼长−0.42\text{黑夜} = \frac{1 - \text{昼长} - 0.4}{2}

lerp(a, b, t):线性插值。t=0 时结果=a,t=1 时结果=b,t=0.5 时取中间值。相当于"按比例混合两个数"。

cos(x):余弦函数,使昼长随季节呈平滑的波浪形变化,夏季最大、冬季最小。

其中:距夏至偏移为当前时间与夏至中点的差距(0=夏至,0.5=冬至)。默认一天20分钟,各阶段时长如下:

季节昼长占比白天时长黑夜时长
夏季~40%~8 分钟~4 分钟
春秋~30%~6 分钟~6 分钟
冬季~20%~4 分钟~8 分钟

冬季黑夜长达8分钟,意味着你在黑暗中活动的时间翻倍,光源和庇护所的重要性急剧上升。夏季则有更多时间进行户外采集和建造。

降水系统 ​

雨和雪不只是视觉效果——它们会改变方块状态、影响能见度、触发闪电。理解降水规律,你就能在暴雨来临前回到屋内。

降水类型判定 ​

每个位置的降水类型根据当地有效温度和湿度决定:

降水类型={雪若该处冻结(有效温度≤0)雨若温度≤8 或湿度≥8无其他情况\text{降水类型} = \begin{cases} \text{雪} & \text{若该处冻结(有效温度} \le 0\text{)} \\ \text{雨} & \text{若温度} \le 8\ \text{或湿度} \ge 8 \\ \text{无} & \text{其他情况} \end{cases}

其中:有效温度 = 基础温度 + 季节修正 + 海拔修正;温度和湿度为当地季节温湿度值(0~15)。

注意:即使在热带,只要海拔足够高(有效温度≤0),降水就会变成雪。反之,地下深处永远温暖,不会下雪。

季节对降水的影响 ​

UpdatePrecipitation 方法按季节设定不同的降水频率和闪电概率:

季节降水间隔倍率闪电强度倍率闪电出现概率
夏季1.01.050%
秋季1.51.050%
冬季1.000%
春季1.52.0100%

其中:降水间隔倍率越大则两次降水之间等待越久;闪电强度倍率决定闪电的频繁程度;闪电出现概率表示一场降水是否伴随闪电。

春季是全年雷雨最频繁的季节——闪电强度倍率高达2,且100%出现。冬季从不下闪电(强度倍率为0),因为暴雪不具备闪电条件。

降水周期 ​

每次降水事件持续约3~6游戏分钟,间隔因季节而异:

降水持续时间=60×random(3, 6) 秒\text{降水持续时间} = 60 \times \mathrm{random}(3,\ 6)\ \text{秒}

降水间隔=60×random(5, 45)季节倍率 秒\text{降水间隔} = \frac{60 \times \mathrm{random}(5,\ 45)}{\text{季节倍率}}\ \text{秒}

random(a, b):游戏引擎中的随机数函数(对应源码 m_random.Float(a, b)),返回 a 到 b 之间的随机浮点数,每次调用结果不同。本文后续所有 random 均指此类随机数函数

  • random.Float(a,b) 返回区间内随机浮点数。
  • random.Int(a,b) 返回区间内随机整数。
  • random.Bool(p) 以概率 p(0~1)返回 true/false。

其中:季节倍率见上表(夏季/冬季为1.0,春/秋为1.5)。

参数值
单次降水时长3~6 分钟
两次降水间隔(夏/冬)5~45 分钟
两次降水间隔(春/秋)3.3~30 分钟
降水淡入/淡出10~30 秒

困难模式下,首次降水来得更快(出生0~2分钟后),且闪电更强。

闪电系统 ​

春季的雷暴不只是吓人——闪电真的会劈中地面,引发火灾。了解闪电触发条件,你就能评估在户外活动的风险。

闪电触发条件 ​

UpdateLightning 方法控制闪电生成:

闪电触发需同时满足两个条件:

降水强度=1\text{降水强度} = 1

每秒判定:random.Bool(m闪电×0.0002)=true\text{每秒判定:}\mathrm{random.Bool}(m_{\text{闪电}} \times 0.0002) = \text{true}

其中:降水强度为当前降水的最大强度(0~1,满强度为1);m_闪电为闪电强度参数,由季节和难度决定(春季可达2.0,夏季/秋季约0.33~0.66,冬季为0)。每秒对每个已加载区块执行一次判定。

闪电只在降水达到满强度时才会触发。每秒每个已加载区块有约 0.02%~0.04% 的概率被闪电击中,春季翻倍。闪电会劈向该区域内最高的方块。

人工触发 ​

玩家可以通过某些模组或编辑器功能手动召唤闪电,会在前方32格范围内的最高点生成。

雾系统 ​

浓雾会大幅降低能见度,让导航和寻路变得困难。雾在秋冬更常见,且往往持续更久。

雾的周期 ​

UpdateFog 方法控制雾的生成:

雾间隔倍率={1.75若秋季或冬季1.0若夏季或春季\text{雾间隔倍率} = \begin{cases} 1.75 & \text{若秋季或冬季} \\ 1.0 & \text{若夏季或春季} \end{cases}

雾开始时间=60×random(10, 40)雾间隔倍率\text{雾开始时间} = \frac{60 \times \mathrm{random}(10,\ 40)}{\text{雾间隔倍率}}

雾持续时间=60×random(4, 7)×雾间隔倍率\text{雾持续时间} = 60 \times \mathrm{random}(4,\ 7) \times \text{雾间隔倍率}

其中:雾间隔倍率秋冬更高意味着雾更频繁;random为范围内的随机值。默认参数下:

季节雾间隔雾持续时间
夏/春10~40 分钟4~7 分钟
秋/冬6~23 分钟7~12 分钟

秋冬季节不仅雾更频繁,单次持续时间也更长。雾的淡入/淡出需要20~40秒,不会突然出现。

冰雪与地形互动 ​

天气不只是天空中的景象——它会真实地改变你脚下的方块。水会结冰,地面会积雪,温度回升后它们又会消失。

冰冻与融化 ​

FreezeThawAndDepositSnow 方法在每个区块加载和扫描时执行:

冻结判定  ⟺  该位置当前下雪 且 random.Bool(冻结概率)=true\text{冻结判定} \iff \text{该位置当前下雪}\ \text{且}\ \mathrm{random.Bool}(\text{冻结概率}) = \text{true}

融化判定  ⟺  该位置当前不下雪 且 random.Bool(融化概率)=true\text{融化判定} \iff \text{该位置当前不下雪}\ \text{且}\ \mathrm{random.Bool}(\text{融化概率}) = \text{true}

random.Bool(p) 以概率 p 返回 true(即"掷骰子",p 越大越容易触发);冻结概率和融化概率由调用时机决定(区块首次加载时为1.0即必定触发,后续周期扫描时为0.66即约三分之二概率触发)。

下雪时的地形变化 ​

条件变化
水面(距海岸>35格)结冰 → 冰块(62)
可支撑雪的方块上方覆盖一层雪(61)
可被雪替换的方块替换为雪(61)

融化时的地形变化 ​

条件变化
雪方块(61)消失(DestroyCell)
冰块(62)消失(DestroyCell,不触发掉落)

冰雪变化只在"生态环境行为模式"为 Living 时生效。如果关闭了天气效果,新生成的区块不会积雪,但已有冰雪不会自动融化。

世界设置参数 ​

在创建世界时,你可以调整以下参数来定制天气与季节体验。

参数默认值作用
季节变化开启关闭后季节永远停留在当前状态
年天数24一年有多少游戏天,越大则季节更替越慢
天气效果开启关闭后无降水、无雾、无闪电、无冰雪变化
时间流逝变化可选固定白天/黑夜/日出/日落,或正常循环
出生点难度简单困难模式下首次降水来得更快、闪电更强

其中:年天数直接控制季节更替速度。设为48则一个季节持续12天(现实4小时),节奏更舒缓;设为12则一个季节仅3天(现实1小时),节奏更紧凑。

写给开发者 ​

如果你计划开发天气模组或自定义环境行为,以下技术细节将帮助你快速理解系统架构。

资料暂存

本小节内容暂时存放于此,后续会移动至"MOD开发"章节。

开发者指南

核心文件索引 ​

文件职责
SubsystemWeather.cs天气系统主类:降水、闪电、雾、雨雪粒子、地形冰冻/融化
SubsystemSeasons.cs季节划分与 TimeOfYear → Season 转换
SubsystemTimeOfDay.cs昼夜循环与季节对昼长的影响
SubsystemTime.cs游戏时间流逝、睡眠加速、暂停菜单减速
WorldSettings.cs世界参数定义(年天数、天气开关、季节开关)
TerrainUpdater.cs季节温度曲线(TemperatureCurve)定义

降水系统完整逻辑 ​

csharp
// UpdatePrecipitation 核心逻辑(简化)
if (当前时间 > 降水结束时间) {
    switch (季节) {
        case 夏季: num=1f;   num2=1f; probability=0.5f; break;
        case 秋季: num=1.5f; num2=1f; probability=0.5f; break;
        case 冬季: num=1f;   num2=0f; probability=0f;   break;
        case 春季: num=1.5f; num2=2f; probability=1f;   break;
    }
    // 首次降水(endTime==0)与后续降水的间隔不同
    // 困难模式首次等待更短
    m_precipitationStartTime = 当前时间 + 60f * random(5f, 45f) / num;
    m_precipitationEndTime = m_precipitationStartTime + 60f * random(3f, 6f);
    m_lightningIntensity = random.Bool(probability) 
        ? Saturate(random.Float(0.33f, 1f) * num2) : 0f;
}
// 降水强度淡入淡出
if (IsPrecipitationStarted) {
    PrecipitationIntensity += dt / m_precipitationRampTime;
} else {
    PrecipitationIntensity -= dt / m_precipitationRampTime;
}
PrecipitationIntensity = Saturate(PrecipitationIntensity);

闪电触发完整逻辑 ​

csharp
// UpdateLightning 核心逻辑
if (PrecipitationIntensity != 1f) return;
if (!PeriodicGameTimeEvent(1.0, 0.0)) return;  // 每秒检查一次
TerrainChunk chunk = 随机选择一个已加载区块;
if (!random.Bool(m_lightningIntensity * 0.0002f)) return;
// 在 16x16 区域内找最高点
Vector3? target = null;
for (int x = num-8; x < num+8; x++) {
    for (int z = num2-8; z < num2+8; z++) {
        int top = terrain.GetTopHeight(x, z);
        if (!target.HasValue || top > target.Value.Y) {
            target = new Vector3(x, top, z);
        }
    }
}
if (target.HasValue) {
    SubsystemSky.MakeLightningStrike(target.Value, false);
}

昼夜阶段计算 ​

csharp
// UpdateStarts 核心逻辑
float num = Midpoint(SummerStart, AutumnStart);  // 夏至中点
float num2 = Remainder(TimeOfYear - num, 1f);    // 距夏至偏移
float dayLength = Lerp(0.2f, 0.4f, 0.5f + 0.5f * Cos(2π * num2));
float duskDawnTotal = 0.4f;
float nightLength = (1f - (dayLength + duskDawnTotal)) / 2f;
DayStart = 0.3f;
DawnStart = Add(DayStart, -nightLength);   // 黎明开始
DuskStart = Add(DayStart, dayLength);       // 黄昏开始
NightStart = Add(DuskStart, nightLength);   // 黑夜开始

温度传递链 ​

csharp
// 从季节到冰冻判定的完整链路
WorldSettings.TimeOfYear (0~1)
    → SubsystemSeasons.TimeOfYearToSeason() → Season + TimeOfSeason
    → TerrainUpdater.TemperatureCurve.Sample(TimeOfYear) → SeasonTemperature
    → Terrain.SeasonTemperature = value
    → Terrain.GetSeasonalTemperature(x, z) = GetTemperature(x, z) + SeasonTemperature
    → SubsystemWeather.GetPrecipitationShaftInfo(x, z)
        → IsPlaceFrozen(seasonalTemp, topHeight)
            → temperature + GetTemperatureAdjustmentAtHeight(y) <= 0
    → 决定降水类型(雪/雨/无)

降水类型判定完整逻辑 ​

csharp
// GetPrecipitationShaftInfo
int seasonalTemp = terrain.GetSeasonalTemperature(shaftValue);
int topHeight = Terrain.ExtractTopHeight(shaftValue);
if (IsPlaceFrozen(seasonalTemp, topHeight)) {
    return { Type=Snow, Intensity=PrecipitationIntensity };
}
int seasonalHumidity = terrain.GetSeasonalHumidity(shaftValue);
if (seasonalTemp <= 8 || seasonalHumidity >= 8) {
    return { Type=Rain, Intensity=PrecipitationIntensity };
}
return { Type=Rain, Intensity=0f };  // 无降水

继续阅读地形与气候、建筑与取暖和衣物与盔甲图鉴。

英文 Wiki 原条目 ​

参与共建发现错误或有建议?两种零门槛方式,无需本地环境

玩家共建文档 · 原版、插件版、联机版与插件联机版请注意区分