天气不是屏幕前面飘几条雨线
Phaser 游戏做天气很容易从粒子开始:下雨就发射蓝色线条,下雪就飘白点,刮风就让粒子斜一点。这样的视觉能让截图好看,却很容易和玩法脱节。玩家明明看到暴雨,地面却不湿滑;雪天没有脚印;风很大但弹道不受影响;低端手机雨粒子一多就掉帧。天气系统如果只是装饰,会显得廉价;如果每个天气都临时改玩法,又会很快失控。
更稳的做法是把天气拆成三个层次:环境状态、表现层和玩法修正。环境状态描述当前区域是晴、雨、暴雨、雪、雾、沙尘,强度是多少,风向风速是多少,持续到什么时候。表现层根据状态播放粒子、遮罩、音效和地面效果。玩法修正根据同一状态影响摩擦、视野、火焰持续、脚步声、弹道或 NPC 行为。这样天气既有观感,也有规则来源。
天气状态要独立于 Scene
天气通常跨场景存在。玩家从村庄走进森林,雨不应突然重置;打开菜单回来,风声不应叠两遍。WeatherService 应作为全局服务保存当前天气和过渡。Scene 启动时订阅天气状态,创建本场景需要的表现对象;Scene 销毁时清理表现,但不改变天气本身。这样大地图、战斗、营地、室内外切换都能共享环境规则。
天气还可以有局部覆盖。室外大雨,进入山洞后视觉雨粒子关闭,但洞口仍能听到雨声,地面湿滑可能降低。进入火山区域,天气服务仍记录世界天气,但区域环境覆盖为高温烟尘。不要让每个 Scene 自己决定“现在是什么天气”,而是让它声明自己如何响应世界天气。
flowchart TD
A["WeatherTimeline / ServerConfig"] --> B["WeatherService:状态、强度、风向"]
B --> C["VisualWeatherLayer:雨雪粒子、雾、地面水花"]
B --> D["AudioAmbience:雨声、风声、雷声"]
B --> E["GameplayModifier:摩擦、视野、火焰、弹道"]
E --> F["Movement / Combat / AI 系统"]
C --> G["Phaser Scene 渲染"]
D --> G
H["PerformanceProfile"] --> C
视觉层要分前景、背景和地面
雨雪效果如果只在屏幕前景发粒子,会像贴了一层滤镜。更可信的天气通常分三层:背景远处的雾或雨幕,中景的可见雨线,地面上的涟漪、水花、积雪或脚印。Phaser 可以用 ParticleEmitter、TileSprite、RenderTexture 和简单覆盖层组合。前景粒子数量不用太多,地面反馈反而更能让天气“落地”。
天气表现要跟镜头走,但不要完全贴死。前景雨可以相对相机固定,地面水花应该在世界坐标上。否则玩家移动时会发现雨像贴在屏幕玻璃上。风向变化时,粒子角度和速度要平滑过渡,不要突然从左斜变右斜。
玩法修正要可控
天气影响玩法时,要谨慎。小雨可以只是表现;暴雨可以降低火焰伤害、提高脚步声掩盖、让泥地更滑;大雾可以降低敌人视野;大风可以影响轻型投射物。每个修正都应有配置,并有 UI 或环境提示。不要让玩家在没有预告的情况下因为雨天地面湿滑掉坑。天气带来的难度变化必须可读。
不同玩法对天气影响的接受度不同。硬核生存可以让暴雪影响体温和视野;休闲平台跳跃只适合轻微视觉变化。天气系统应支持每个关卡选择哪些修正生效。否则一个全局“雨天摩擦降低”可能破坏精心设计的平台关。
一个天气修正模型
下面的代码展示如何把天气状态转换为玩法修正。各系统读取修正,而不是直接判断天气字符串。
type WeatherKind = "clear" | "rain" | "storm" | "snow" | "fog";
interface WeatherState {
kind: WeatherKind;
intensity: number;
windX: number;
windY: number;
}
interface WeatherModifiers {
groundGripMultiplier: number;
visionMultiplier: number;
fireDurationMultiplier: number;
projectileWind: { x: number; y: number };
}
export function resolveWeatherModifiers(state: WeatherState): WeatherModifiers {
const wet = state.kind === "rain" || state.kind === "storm";
const foggy = state.kind === "fog" || state.kind === "snow";
return {
groundGripMultiplier: wet ? 1 - state.intensity * 0.25 : 1,
visionMultiplier: foggy ? 1 - state.intensity * 0.45 : 1,
fireDurationMultiplier: wet ? 1 - state.intensity * 0.5 : 1,
projectileWind: { x: state.windX * state.intensity, y: state.windY * state.intensity },
};
}
这样 MovementSystem 只看 groundGripMultiplier,AI 只看 visionMultiplier,火焰系统只看 fireDurationMultiplier。如果未来新增沙尘暴,不需要让所有系统识别新天气名,只要修正解析器输出对应数值。
天气过渡比瞬间切换更重要
天气变化要有过渡。晴天到小雨可以先变暗、风声增强、几滴雨出现,再逐渐加密;暴雨停止后,地面湿润效果还可以保留一段时间。瞬间切换会显得像开关。WeatherService 可以保存 current 和 target,用几秒到几十秒插值强度。玩法修正也跟着平滑变化,避免玩家速度突然变慢。
雷暴这类事件可以叠加在雨天之上。雷声、闪电、短暂全局光照、敌人反应都可以由 WeatherEvent 触发。注意闪电频率和亮度,避免光敏问题。提供关闭强闪烁或降低亮度的设置是必要的。
性能降级要提前设计
天气是性能大户。粒子、透明覆盖、后处理、动态灯光都会增加压力。低端机不应完全关闭天气规则,但可以降低表现:减少粒子数量、关闭地面涟漪、降低雾层分辨率、关闭动态水花。WeatherVisualLayer 应根据 PerformanceProfile 选择方案。不要让玩法修正跟着视觉降级消失,否则低端机玩家规则不同。
粒子对象也要池化或由 Phaser 粒子系统管理。不要每滴雨创建 Sprite。屏幕外粒子不要参与复杂碰撞。地面水花可以只在玩家附近生成,不需要全地图模拟。天气看起来覆盖全世界,实际只需要在玩家视野附近表现。
调试和内容工具
开发模式应能切换天气、调整强度、风向、粒子数量和玩法修正开关。显示当前天气状态、目标状态、过渡时间、视觉层对象数、修正值。关卡设计师可以在同一关卡里测试晴天、雨天和雾天,判断是否影响可读性。没有工具,天气很容易变成“上线前美术加一点”的不可控装饰。
还可以做天气回放。记录 5 分钟内天气变化和玩家位置,复现“某次雨天跳跃手感不对”。如果天气来自服务端活动配置,日志里记录 weatherConfigVersion。天气虽然看起来是表现,但一旦影响玩法,就必须可追踪。
上线前检查清单
确认天气状态独立于 Scene;确认视觉层、音频层、玩法修正都来自同一状态;确认室内外和区域覆盖有规则;确认天气过渡平滑;确认玩法修正有 UI 或环境提示;确认低端机只降级视觉不改变规则;确认粒子数量有预算;确认调试面板能切换天气并显示修正;确认光敏设置能降低闪电和强闪烁;确认天气配置版本进入日志。
天气系统的价值是让世界更有呼吸感。Phaser 能很快做出雨雪效果,但真正可信的环境来自状态、表现和玩法的统一。让雨不只是屏幕上的线条,而是世界规则的一部分,玩家才会记住那场雨。
天气和关卡目标的关系
天气如果影响玩法,就可能影响关卡目标。比如限时赛道遇到雨天会更难,潜行关卡遇到雾天会更简单,火焰谜题在暴雨中可能无法完成。关卡设计要声明天气策略:固定天气、随机天气、剧情天气或禁用玩法修正。不要让全局随机天气破坏精心设计的关卡。进入关卡时,WeatherService 可以创建局部 weather context,关卡结束后再恢复世界天气。
任务系统也要知道天气。某些 NPC 只在雨天出现,某些材料只在雪后刷新,某些怪物怕雷暴。任务追踪可以显示“等待雨天”或“暴雨时前往山顶”。如果天气只是随机,玩家会觉得被时间卡住;如果有天气预报或可触发道具,天气就变成策略。客户端展示预报时,必须和实际 WeatherTimeline 同源。
地面积累和后效
天气结束后,世界不一定立即恢复。雨停后地面仍湿,雪停后积雪保留,沙尘后视野慢慢清晰。这些后效能增强真实感,也能形成玩法窗口。可以把天气影响拆成当前天气和环境积累值,比如 wetness、snowCover、dustLevel。当前天气推动积累值变化,积累值再影响地面表现和玩法修正。
积累值要有区域边界。室内不积雪,桥下少雨,洞穴湿度变化慢。Phaser 表现上可以用地面覆盖层、脚印、轮胎印和水花表达。不要全图一刀切。即使实现简化,也可以先在主要区域做差异,让玩家感到天气确实落在世界上。
多人和同步边界
如果游戏有联机或排行榜,天气必须同步。所有玩家在同一场比赛中应看到同样风向和湿滑规则。天气随机源和时间线由服务端或房主决定,客户端只表现。若客户端自行随机,弹道和移动结果会分歧。单机游戏可以本地随机,但保存时记录天气状态,读档后不要突然变天。
天气同步也要处理迟到玩家。玩家中途加入房间,应收到当前天气、目标天气、过渡进度和积累值,而不是从晴天重新过渡。天气看似环境效果,一旦影响玩法,就属于同步状态。
天气预报和玩家计划
如果天气影响玩法,玩家需要计划工具。天气预报可以显示未来几个游戏小时的大致趋势:小雨、暴雨、转晴。预报不必百分百准确,但要足够可靠,让玩家决定是否出门、是否挑战某关、是否种植某作物。预报 UI 可以放在地图、营地公告板或 HUD 小图标中。
天气预报也能减少随机挫败。玩家准备火焰关卡时,看到即将暴雨,就能选择等待或换装备。没有预报,天气变化会像系统随机惩罚。环境系统越影响规则,就越要给玩家信息。
美术资源的复用策略
天气资源不要为每张地图完全重做。雨线、雪粒、雾层、雷光可以是通用资源,地面涟漪、积雪边缘和脚印按地形定制。配置把天气表现和场景地表类型组合起来。比如石路雨天有水花,草地雨天颜色变深,沙地雨天变泥。这样复用高,表现也有差异。
资源加载也要按天气预取。如果天气预报显示马上下雪,可以提前加载雪粒子和覆盖层。不要等状态切换时才加载,造成第一次下雪卡顿。天气系统和资源加载系统应有轻量联动。
天气调试与 QA 场景
QA 需要能固定天气,而不是等随机系统。每个关卡测试用例都应覆盖默认天气和最影响玩法的天气,例如雨天湿滑、雾天低视野、雪天低对比。调试面板提供“锁定天气”“跳到下一次变化”“显示当前修正值”。这样才能判断关卡在不同环境下是否仍然公平。
截图对比也有价值。同一地点在晴天、雨天、雾天各截一张,能快速发现 UI 对比度、敌人轮廓和地面危险提示是否被天气遮住。天气越漂亮,越要检查可读性。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。