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:
@@ -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
|
||||
Reference in New Issue
Block a user