134 lines
3.8 KiB
GDScript
134 lines
3.8 KiB
GDScript
## 全局时间系统(Autoload 单例)。
|
||
## 负责游戏时间的推进与播报,仅在世界场景中运行。
|
||
## 历法:12 月 × 30 日 = 360 日/年。
|
||
extends Node
|
||
|
||
## 每当推进一日后发出。
|
||
## @param year: 当前年份
|
||
## @param month: 当前月份(1-12)
|
||
## @param day: 当前日(1-30)
|
||
signal day_passed(year: int, month: int, day: int)
|
||
## 每当进入新月份时发出(同一天内 day_passed 之后)。
|
||
## @param year: 当前年份
|
||
## @param month: 当前月份(1-12)
|
||
signal month_passed(year: int, month: int)
|
||
## 每当进入新年份时发出(同一天内 month_passed 之后)。
|
||
## @param year: 当前年份
|
||
signal year_passed(year: int)
|
||
## 时间流速档位变化时发出。
|
||
## @param speed_index: 新档位在 SPEEDS 中的索引
|
||
signal speed_changed(speed_index: int)
|
||
## 暂停状态变化时发出。
|
||
## @param paused: 是否已暂停
|
||
signal pause_changed(paused: bool)
|
||
|
||
## 可选的时间流速倍率档位。
|
||
const SPEEDS := [1.0, 5.0, 20.0]
|
||
## 每月的天数。
|
||
const DAYS_PER_MONTH := 30
|
||
## 每年的月数。
|
||
const MONTHS_PER_YEAR := 12
|
||
## 现实世界每 1 天对应的时长(秒)。
|
||
const DAY_LENGTH := 0.5
|
||
|
||
## 当前流速档位在 SPEEDS 中的索引。
|
||
var speed_index := 0
|
||
## 当前流速倍率(与 SPEEDS[speed_index] 保持一致)。
|
||
var speed := 1.0
|
||
## 是否暂停时间推进。
|
||
var paused := false
|
||
## 已累积的现实时间(秒),未满 1 天。
|
||
var _elapsed := 0.0
|
||
|
||
|
||
func _process(delta: float) -> void:
|
||
if paused or not _is_in_game():
|
||
return
|
||
_elapsed += delta * speed
|
||
if _elapsed >= DAY_LENGTH:
|
||
_elapsed -= DAY_LENGTH
|
||
_advance()
|
||
|
||
|
||
## 判断当前场景是否为游戏世界场景(主菜单/存档界面不推进时间)。
|
||
func _is_in_game() -> bool:
|
||
var scene := get_tree().current_scene
|
||
return scene != null and scene.name == "MainGame"
|
||
|
||
|
||
## 推进一日并广播对应信号,跨月/跨年时补发 month_passed / year_passed。
|
||
func _advance() -> void:
|
||
var new_month := false
|
||
var new_year := false
|
||
GameState.day += 1
|
||
if GameState.day > DAYS_PER_MONTH:
|
||
GameState.day = 1
|
||
GameState.month += 1
|
||
new_month = true
|
||
if GameState.month > MONTHS_PER_YEAR:
|
||
GameState.month = 1
|
||
GameState.year += 1
|
||
new_year = true
|
||
day_passed.emit(GameState.year, GameState.month, GameState.day)
|
||
if new_month:
|
||
month_passed.emit(GameState.year, GameState.month)
|
||
if new_year:
|
||
year_passed.emit(GameState.year)
|
||
|
||
|
||
## 循环切换下一档流速,返回新倍率。
|
||
func cycle_speed() -> float:
|
||
speed_index = (speed_index + 1) % SPEEDS.size()
|
||
speed = SPEEDS[speed_index]
|
||
speed_changed.emit(speed_index)
|
||
return speed
|
||
|
||
|
||
## 直接设置流速档位(越界自动钳制)。
|
||
## @param index: 目标档位索引
|
||
func set_speed_index(index: int) -> void:
|
||
speed_index = clampi(index, 0, SPEEDS.size() - 1)
|
||
speed = SPEEDS[speed_index]
|
||
speed_changed.emit(speed_index)
|
||
|
||
|
||
## 切换暂停状态,返回切换后的暂停状态。
|
||
func toggle_pause() -> bool:
|
||
paused = not paused
|
||
pause_changed.emit(paused)
|
||
return paused
|
||
|
||
|
||
## 显式设置暂停状态(幂等,状态未变化时不发信号)。
|
||
## @param value: 目标暂停状态
|
||
func set_paused(value: bool) -> void:
|
||
if paused == value:
|
||
return
|
||
paused = value
|
||
pause_changed.emit(paused)
|
||
|
||
|
||
## 当前流速的显示文本,如 "x5"。
|
||
func get_speed_label() -> String:
|
||
return "x%d" % int(speed)
|
||
|
||
|
||
## 当前日期数组 [年, 月, 日]。
|
||
func get_current_date() -> Array:
|
||
return [GameState.year, GameState.month, GameState.day]
|
||
|
||
|
||
## 当前日期文本,如 "3年 5月 12日"。
|
||
func get_date_text() -> String:
|
||
return "%d年 %d月 %d日" % [GameState.year, GameState.month, GameState.day]
|
||
|
||
|
||
## 直接设置日期(供读档/测试使用)。
|
||
## @param y: 年
|
||
## @param m: 月(1-12)
|
||
## @param d: 日(1-30)
|
||
func set_date(y: int, m: int, d: int) -> void:
|
||
GameState.year = y
|
||
GameState.month = m
|
||
GameState.day = d
|