Refactor game scripts and update vault scene structure. Enhanced organization of game logic by separating data and rendering responsibilities across multiple scripts. Removed unused background assets and updated vault scene to include new game clock and weather system functionalities.

This commit is contained in:
Leonid Pershin
2026-08-11 10:18:30 +03:00
parent 709776116b
commit a81747781d
48 changed files with 979 additions and 4509 deletions
+148
View File
@@ -0,0 +1,148 @@
class_name WeatherSystem
extends Node
## Погода: текущий тип, плавные переходы и смена по игровому времени.
##
## Данные и правила, без отрисовки. Вид (surface_view.gd, sky_view.gd) читает
## отсюда `clouds`, `precipitation`, `fog` и `wind` и рисует по ним.
##
## Такт берётся у GameClock, поэтому погода стоит вместе с паузой и ускоряется
## вместе со скоростью игры — своего таймера здесь нет намеренно.
enum Kind { CLEAR, CLOUDY, OVERCAST, RAIN, STORM, FOG, SNOW }
## Целевые параметры каждого типа. `clouds` — плотность облаков, `precipitation`
## — сила осадков, `fog` — дымка у горизонта, `wind` — скорость сноса.
const KINDS := {
Kind.CLEAR: {"label": "Ясно", "clouds": 0.12, "precipitation": 0.0, "fog": 0.0, "wind": 0.3},
Kind.CLOUDY: {"label": "Облачно", "clouds": 0.45, "precipitation": 0.0, "fog": 0.0, "wind": 0.5},
Kind.OVERCAST: {"label": "Пасмурно", "clouds": 0.85, "precipitation": 0.0, "fog": 0.06, "wind": 0.4},
Kind.RAIN: {"label": "Дождь", "clouds": 0.95, "precipitation": 0.55, "fog": 0.14, "wind": 0.7},
Kind.STORM: {"label": "Ливень", "clouds": 1.0, "precipitation": 1.0, "fog": 0.22, "wind": 1.0},
Kind.FOG: {"label": "Туман", "clouds": 0.3, "precipitation": 0.0, "fog": 0.62, "wind": 0.12},
Kind.SNOW: {"label": "Снег", "clouds": 0.9, "precipitation": 0.5, "fog": 0.24, "wind": 0.35},
}
## Куда погода может перейти и с каким относительным весом. Матрица, а не
## общий мешок: так дождь приходит через пасмурно, а не из ясного неба.
const TRANSITIONS := {
Kind.CLEAR: {Kind.CLEAR: 4, Kind.CLOUDY: 5, Kind.FOG: 1},
Kind.CLOUDY: {Kind.CLEAR: 4, Kind.CLOUDY: 2, Kind.OVERCAST: 4, Kind.FOG: 1},
Kind.OVERCAST: {Kind.CLOUDY: 4, Kind.OVERCAST: 2, Kind.RAIN: 3, Kind.SNOW: 2},
Kind.RAIN: {Kind.RAIN: 2, Kind.STORM: 2, Kind.OVERCAST: 5},
Kind.STORM: {Kind.RAIN: 5, Kind.OVERCAST: 2},
Kind.FOG: {Kind.FOG: 2, Kind.CLEAR: 4, Kind.CLOUDY: 3},
Kind.SNOW: {Kind.SNOW: 3, Kind.OVERCAST: 4, Kind.CLOUDY: 2},
}
## Месяцы, когда осадки выпадают снегом.
const WINTER_MONTHS: Array[int] = [11, 12, 1, 2]
const MIN_DURATION := 120
const MAX_DURATION := 420
## За сколько игровых минут параметры доходят до целевых.
const BLEND_MINUTES := 45.0
## Сменился тип погоды — для HUD и звука.
signal changed(kind: int)
var kind := Kind.CLEAR
var clouds := 0.12
var precipitation := 0.0
var fog := 0.0
var wind := 0.3
var _minutes_left := MIN_DURATION
var _rng := RandomNumberGenerator.new()
var _clock: GameClock
func _ready() -> void:
_rng.randomize()
_apply_target(1.0)
## Сцена связывает погоду с часами: без этого она стоит на месте.
func attach_clock(clock: GameClock) -> void:
_clock = clock
_clock.minute_passed.connect(_on_minute_passed)
func label() -> String:
return String(KINDS[kind]["label"])
## Идёт ли снег, а не дождь — виду нужно рисовать разное.
func is_snowing() -> bool:
return kind == Kind.SNOW
func save_data() -> Dictionary:
return {
"kind": int(kind),
"minutes_left": _minutes_left,
"clouds": clouds,
"precipitation": precipitation,
"fog": fog,
"wind": wind,
}
func load_data(data: Dictionary) -> void:
kind = clampi(int(data.get("kind", Kind.CLEAR)), 0, KINDS.size() - 1)
_minutes_left = int(data.get("minutes_left", MIN_DURATION))
clouds = float(data.get("clouds", 0.12))
precipitation = float(data.get("precipitation", 0.0))
fog = float(data.get("fog", 0.0))
wind = float(data.get("wind", 0.3))
changed.emit(kind)
# --- Внутреннее -------------------------------------------------------------
func _on_minute_passed(_total_minutes: int) -> void:
_blend_toward_target()
_minutes_left -= 1
if _minutes_left > 0:
return
kind = _roll_next()
_minutes_left = _rng.randi_range(MIN_DURATION, MAX_DURATION)
changed.emit(kind)
## Параметры не прыгают вместе с типом: они доходят до цели за BLEND_MINUTES.
func _blend_toward_target() -> void:
_apply_target(1.0 / BLEND_MINUTES)
func _apply_target(weight: float) -> void:
var target: Dictionary = KINDS[kind]
clouds = lerpf(clouds, float(target["clouds"]), weight)
precipitation = lerpf(precipitation, float(target["precipitation"]), weight)
fog = lerpf(fog, float(target["fog"]), weight)
wind = lerpf(wind, float(target["wind"]), weight)
func _roll_next() -> int:
var options: Dictionary = TRANSITIONS[kind]
var total := 0
for weight: int in options.values():
total += weight
var pick := _rng.randi_range(1, total)
for candidate: int in options:
pick -= int(options[candidate])
if pick <= 0:
return _seasonal(candidate)
return kind
## Снег уместен только зимой; в остальное время он превращается в дождь.
func _seasonal(candidate: int) -> int:
if candidate != Kind.SNOW:
return candidate
if _clock == null:
return Kind.RAIN
var month := int(_clock.now()["month"])
return Kind.SNOW if WINTER_MONTHS.has(month) else Kind.RAIN