Files
mtgodot-poc/project/weather_daynight_system.gd
T
shenandshen 66d217b313 feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复:
  - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight
  - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程
  - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题
  - 新增 test_bridge_height_parity.gd 自动化对拍测试
- 40250 怪物击杀经验动效:
  - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附
- 40250 客户端全系统功能对齐(Batches 1-31):
  - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试
- 文档沉淀:
  - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
2026-09-19 08:51:25 -07:00

169 lines
5.3 KiB
GDScript

# weather_daynight_system.gd —— Metin2 40250 单机本地天候昼夜交替与地图环境特效系统 1:1
# 对照 40250 客户端 PythonBackground.cpp, game.py, environment.h
class_name WeatherDayNightSystem
extends RefCounted
signal phase_changed(old_phase: String, new_phase: String)
signal weather_changed(old_weather: String, new_weather: String)
signal lighting_updated(sun_color: Color, sun_energy: float, ambient_color: Color, fog_density: float)
const PHASE_DAWN := "dawn" # 黎明晨曦 (05:00 ~ 08:00)
const PHASE_NOON := "noon" # 正午晴空 (08:00 ~ 17:00)
const PHASE_DUSK := "dusk" # 黄昏落日 (17:00 ~ 20:00)
const PHASE_NIGHT := "night" # 寂静黑夜 (20:00 ~ 05:00)
const WEATHER_CLEAR := "clear" # 晴朗明净
const WEATHER_RAIN := "rain" # 潇潇细雨
const WEATHER_SNOW := "snow" # 冰山暴雪 (Mount Sohan)
const WEATHER_SANDSTORM := "sandstorm" # 狂沙飞舞 (Yongbi Desert)
const WEATHER_CINDERS := "cinders" # 烈焰余烬 (Doyyumhwan)
const SECONDS_PER_DAY: float = 86400.0
const DEFAULT_TIME_SCALE: float = 60.0 # 默认 1 秒流逝 60 秒游戏时间 (24 分钟一昼夜)
const MAP_DEFAULT_WEATHER: Dictionary = {
"village": WEATHER_CLEAR,
"sohan": WEATHER_SNOW,
"desert": WEATHER_SANDSTORM,
"flame": WEATHER_CINDERS,
"temple": WEATHER_CLEAR,
"catacomb": WEATHER_CLEAR
}
var time_of_day: float = 43200.0 # 默认正午 12:00:00 (12 * 3600)
var time_scale: float = DEFAULT_TIME_SCALE
var is_frozen: bool = false
var current_phase: String = PHASE_NOON
var current_weather: String = WEATHER_CLEAR
var current_map: String = "village"
# 光影参数
var sun_color: Color = Color(1.0, 0.98, 0.9)
var sun_energy: float = 1.2
var ambient_color: Color = Color(0.9, 0.9, 0.95)
var fog_density: float = 0.001
func _init() -> void:
_update_phase_and_lighting()
# 帧心跳更新天候流逝
func update(delta: float) -> void:
if not is_frozen:
time_of_day = fmod(time_of_day + delta * time_scale, SECONDS_PER_DAY)
if time_of_day < 0.0:
time_of_day += SECONDS_PER_DAY
_update_phase_and_lighting()
# 手动设置指定时间 (小时 0~24,分钟 0~60)
func set_time_of_day(hour: float, minute: float = 0.0) -> void:
var clamped_h = clampf(hour, 0.0, 23.99)
var clamped_m = clampf(minute, 0.0, 59.99)
time_of_day = clamped_h * 3600.0 + clamped_m * 60.0
_update_phase_and_lighting()
# 直接快速切换至指定时相
func set_phase(target_phase: String) -> void:
match target_phase:
PHASE_DAWN:
set_time_of_day(6.0, 0.0)
PHASE_NOON:
set_time_of_day(12.0, 0.0)
PHASE_DUSK:
set_time_of_day(18.5, 0.0)
PHASE_NIGHT:
set_time_of_day(23.0, 0.0)
# 设置天气模式
func set_weather(weather_type: String) -> Dictionary:
var valid_weathers = [WEATHER_CLEAR, WEATHER_RAIN, WEATHER_SNOW, WEATHER_SANDSTORM, WEATHER_CINDERS]
if not (weather_type in valid_weathers):
return {"ok": false, "reason": "INVALID_WEATHER_TYPE"}
if current_weather != weather_type:
var old = current_weather
current_weather = weather_type
weather_changed.emit(old, weather_type)
_update_phase_and_lighting()
return {"ok": true, "weather": current_weather}
# 设置当前地图并自动匹配环境天气
func set_map_environment(map_name: String) -> void:
current_map = map_name
var def_weather = MAP_DEFAULT_WEATHER.get(map_name, WEATHER_CLEAR)
set_weather(def_weather)
# 核心昼夜时相与光照参数计算
func _update_phase_and_lighting() -> void:
var hours = time_of_day / 3600.0
var new_phase = PHASE_NOON
if hours >= 5.0 and hours < 8.0:
new_phase = PHASE_DAWN
sun_color = Color(1.0, 0.8, 0.6) # 晨曦暖金
sun_energy = 0.75
ambient_color = Color(0.85, 0.75, 0.65)
fog_density = 0.002
elif hours >= 8.0 and hours < 17.0:
new_phase = PHASE_NOON
sun_color = Color(1.0, 0.98, 0.92) # 正午白炽日光
sun_energy = 1.2
ambient_color = Color(0.9, 0.9, 0.95)
fog_density = 0.001
elif hours >= 17.0 and hours < 20.0:
new_phase = PHASE_DUSK
sun_color = Color(0.95, 0.45, 0.3) # 晚霞橙红
sun_energy = 0.65
ambient_color = Color(0.7, 0.45, 0.4)
fog_density = 0.003
else:
new_phase = PHASE_NIGHT
sun_color = Color(0.3, 0.4, 0.7) # 冷冽月光
sun_energy = 0.25
ambient_color = Color(0.15, 0.2, 0.35)
fog_density = 0.004
# 天气修正
match current_weather:
WEATHER_RAIN:
sun_energy *= 0.6
fog_density += 0.003
WEATHER_SNOW:
sun_color = sun_color.lerp(Color(0.85, 0.9, 1.0), 0.5)
fog_density += 0.002
WEATHER_SANDSTORM:
sun_color = sun_color.lerp(Color(0.85, 0.7, 0.4), 0.6)
fog_density += 0.008
WEATHER_CINDERS:
sun_color = sun_color.lerp(Color(1.0, 0.35, 0.2), 0.5)
fog_density += 0.004
if current_phase != new_phase:
var old = current_phase
current_phase = new_phase
phase_changed.emit(old, new_phase)
lighting_updated.emit(sun_color, sun_energy, ambient_color, fog_density)
# 获取格式化时间字符串 "HH:MM:SS"
func get_time_string() -> String:
var total_sec = int(time_of_day)
var h = int(total_sec / 3600)
var m = int((total_sec % 3600) / 60)
var s = total_sec % 60
return "%02d:%02d:%02d" % [h, m, s]
# 获取当前光照参数字典
func get_current_lighting() -> Dictionary:
return {
"phase": current_phase,
"weather": current_weather,
"time_string": get_time_string(),
"sun_color": sun_color,
"sun_energy": sun_energy,
"ambient_color": ambient_color,
"fog_density": fog_density
}