季节系统
四季循环驱动世界视觉变化。一年 365 天,每季 91 天,循环往复。
概述
季节是世界的"心跳"。它控制:
- 地形 tile 的外观(草地、水面)
- 树木/植物的状态(茂盛、枯黄、枯萎、开花)
- 天气概率(春雨多、冬天雪多)
- 环境粒子(樱花、萤火虫、落叶、飘雪)
- 建筑色调(秋暖冬冷)
时间模型
一年 = 365 天
每季 = 91 天(365 / 4,余1天归春天)
春:Day 0-90
夏:Day 91-181
秋:Day 182-272
冬:Day 273-364季节状态机
ts
type Season = 'spring' | 'summer' | 'autumn' | 'winter';
interface SeasonState {
season: Season;
dayInSeason: number; // 0-90
yearDay: number; // 0-364
year: number; // 第几年
isTransitioning: boolean; // 是否在过渡期
transitionProgress: number; // 0-1,过渡进度
}
function getSeasonState(gameDay: number): SeasonState {
const year = Math.floor(gameDay / 365);
const yearDay = gameDay % 365;
const seasonIndex = Math.floor(yearDay / 91);
const dayInSeason = yearDay % 91;
const seasons: Season[] = ['spring', 'summer', 'autumn', 'winter'];
const TRANSITION_START = 81; // 每季最后10天开始过渡
const TRANSITION_DAYS = 10;
const isTransitioning = dayInSeason >= TRANSITION_START;
const transitionProgress = isTransitioning
? (dayInSeason - TRANSITION_START) / TRANSITION_DAYS
: 0;
return {
season: seasons[seasonIndex],
dayInSeason,
yearDay,
year,
isTransitioning,
transitionProgress,
};
}季节视觉定义
🌸 春 (Day 0-90)
| 元素 | 视觉 |
|---|---|
| 草地 | 嫩绿 #7cba3d → #8fd44f |
| 树木 | 新叶,浅绿树冠,部分开花 |
| 花卉 | 全部绽放(樱花、野花) |
| 水面 | 清澈,浅蓝 |
| 光照 | 暖白,亮度适中 |
| 粒子 | 樱花花瓣飘落(粉色,慢速) |
| 天气倾向 | 30% 晴天、40% 阴天、30% 小雨 |
☀️ 夏 (Day 91-181)
| 元素 | 视觉 |
|---|---|
| 草地 | 深绿 #5a9e2f |
| 树木 | 茂密树冠,深绿 |
| 花卉 | 部分凋谢,保留向日葵等夏季花卉 |
| 水面 | 深蓝,偶有蜻蜓 |
| 光照 | 明亮,偏暖黄 |
| 粒子 | 萤火虫(黄色小点,夜间出没)、蜻蜓 |
| 天气倾向 | 50% 晴天、20% 阴天、20% 雷阵雨、10% 多云 |
🍂 秋 (Day 182-272)
| 元素 | 视觉 |
|---|---|
| 草地 | 枯黄 #c9a66b → #a68a4a |
| 树木 | 红叶/黄叶,逐渐落叶 |
| 花卉 | 大部分凋谢,保留菊花 |
| 水面 | 偏灰,反射落叶 |
| 光照 | 暖橙,黄昏感 |
| 粒子 | 落叶旋转飘落(红/橙/黄,中速) |
| 天气倾向 | 25% 晴天、35% 阴天、25% 小雨、15% 大风 |
❄️ 冬 (Day 273-364)
| 元素 | 视觉 |
|---|---|
| 草地 | 灰白 #d4d4d4 → #e8e8e8 |
| 树木 | 枯枝,积雪覆盖 |
| 花卉 | 全部枯萎,温室除外 |
| 水面 | 部分结冰,偏白蓝 |
| 光照 | 冷蓝,亮度低 |
| 粒子 | 飘雪(白色,慢速)、偶尔暴风雪(密集快速) |
| 天气倾向 | 20% 晴天、30% 阴天、30% 小雪、20% 暴风雪 |
渐变过渡
季节切换不是突变,而是平滑渐变。
过渡时机
每个季节的 最后 10 天(Day 81-90)为过渡期。
春末 (Day 81-90):春 → 夏 草地嫩绿渐变深绿
夏末 (Day 81-90):夏 → 秋 草地深绿渐变枯黄
秋末 (Day 81-90):秋 → 冬 草地枯黄渐变灰白
冬末 (Day 81-90):冬 → 春 草地灰白渐变嫩绿过渡实现
地形 Tile — 交叉淡入淡出
ts
function renderTerrainWithTransition(state: SeasonState) {
const currentSeasonSprite = getSeasonSprite(state.season);
const nextSeasonSprite = getNextSeasonSprite(state.season);
if (state.isTransitioning) {
const t = easeInOutCubic(state.transitionProgress);
currentSeasonSprite.alpha = 1 - t;
nextSeasonSprite.alpha = t;
} else {
currentSeasonSprite.alpha = 1;
nextSeasonSprite.alpha = 0;
}
}
function easeInOutCubic(t: number): number {
return t < 0.5
? 4 * t * t * t
: 1 - Math.pow(-2 * t + 2, 3) / 2;
}建筑 — 色调渐变
ts
function applySeasonTint(building: Sprite, state: SeasonState) {
const tints: Record<Season, number> = {
spring: 0xFFFFFF, // 正常
summer: 0xFFFAE6, // 微暖
autumn: 0xFFE0B2, // 暖橙
winter: 0xD4E5F7, // 冷蓝
};
if (state.isTransitioning) {
const from = tints[state.season];
const to = tints[getNextSeason(state.season)];
building.tint = lerpColor(from, to, easeInOutCubic(state.transitionProgress));
} else {
building.tint = tints[state.season];
}
}雪顶叠加层
ts
function updateSnowOverlay(building: Container, state: SeasonState) {
const snowOverlay = building.getChildByName('snow_overlay');
if (!snowOverlay) return;
if (state.season === 'winter') {
if (state.isTransitioning) {
// 冬末 → 春:雪融化
snowOverlay.alpha = 1 - easeInOutCubic(state.transitionProgress);
} else {
snowOverlay.alpha = 1;
}
} else if (state.season === 'autumn' && state.isTransitioning) {
// 秋末 → 冬:积雪开始
snowOverlay.alpha = easeInOutCubic(state.transitionProgress);
} else {
snowOverlay.alpha = 0;
}
}季节对世界模拟的影响
| 季节 | NPC 行为倾向 | 经济影响 |
|---|---|---|
| 春 | 户外活动增多、播种 | 农产品价格低 |
| 夏 | 工作效率高、夜生活活跃 | 旅游旺季 |
| 秋 | 收获忙碌、储备物资 | 农产品价格高 |
| 冬 | 室内活动多、社交频繁 | 燃料/食物需求高 |
渲染层级(含季节)
1. 地形层(季节化 tile)
2. 道路层
3. 水域层(季节化水面 + 结冰叠加)
4. 建筑底层(阴影)
5. 自然装饰层(季节化树木/花卉/灌木)
6. 建筑主体层(色调滤镜 + 雪顶叠加)
7. 道具层(围栏、路灯等)
8. 角色层
9. 建筑顶层(遮挡角色的屋顶部分)
10. 自然装饰顶层(遮挡角色的树冠)
11. 天气粒子层
12. 天气遮罩层(雾气/色调偏移)
13. UI 层配置参考
ts
// src/config/seasonConfig.ts
export const SEASON_CONFIG = {
DAYS_PER_YEAR: 365,
DAYS_PER_SEASON: 91,
TRANSITION_DAYS: 10,
TRANSITION_START_DAY: 81,
} as const;
export const SEASON_COLORS = {
spring: { grass: '#7cba3d', accent: '#ff9ec4', light: '#fff8f0' },
summer: { grass: '#5a9e2f', accent: '#ffd700', light: '#fffff0' },
autumn: { grass: '#c9a66b', accent: '#ff6b35', light: '#fff0e0' },
winter: { grass: '#d4d4d4', accent: '#87ceeb', light: '#e8f0ff' },
} as const;