Files
g-world/scripts/game/sky_cycle.gd
T

82 lines
3.6 KiB
GDScript

class_name SkyCycle
extends RefCounted
## Палитра неба по времени суток.
##
## Только вычисления, без узлов: по часу суток отдаёт цвета неба, цвет света
## для сцены, яркость звёзд и положение светил. Рисование — в sky_view.gd,
## пейзаж — в surface_view.gd.
## Ключевые моменты суток; между ними всё интерполируется линейно.
## `light` — общий тон, которым красится пейзаж: он делает утро розоватым,
## полдень белым, а ночь синей.
const KEYFRAMES := [
{"hour": 0.0, "top": "#040711", "bottom": "#0b1626", "light": "#4a5876", "stars": 1.0},
{"hour": 4.5, "top": "#070d1e", "bottom": "#1b2340", "light": "#55637f", "stars": 1.0},
{"hour": 6.0, "top": "#16294a", "bottom": "#6b4a68", "light": "#8a7c92", "stars": 0.35},
{"hour": 7.0, "top": "#2c5183", "bottom": "#e0895a", "light": "#d0a184", "stars": 0.0},
{"hour": 9.0, "top": "#3d7cba", "bottom": "#a9d6ec", "light": "#f2f7fa", "stars": 0.0},
{"hour": 13.0, "top": "#4a90d9", "bottom": "#c3e6f5", "light": "#ffffff", "stars": 0.0},
{"hour": 17.0, "top": "#4585c8", "bottom": "#d2e2ec", "light": "#f7efe2", "stars": 0.0},
{"hour": 19.5, "top": "#27456f", "bottom": "#e0734a", "light": "#c78a6e", "stars": 0.05},
{"hour": 21.0, "top": "#0d1a30", "bottom": "#2b2b4c", "light": "#666b8a", "stars": 0.6},
{"hour": 24.0, "top": "#040711", "bottom": "#0b1626", "light": "#4a5876", "stars": 1.0},
]
const SUNRISE := 6.0
const SUNSET := 20.0
## Состояние неба на указанный час суток: top, bottom, light, stars.
static func sample(hour: float) -> Dictionary:
var moment := fposmod(hour, 24.0)
for index in range(KEYFRAMES.size() - 1):
var from: Dictionary = KEYFRAMES[index]
var to: Dictionary = KEYFRAMES[index + 1]
var start := float(from["hour"])
var end := float(to["hour"])
if moment < start or moment > end:
continue
var span := end - start
var weight := 0.0 if is_zero_approx(span) else (moment - start) / span
return {
"top": Color(String(from["top"])).lerp(Color(String(to["top"])), weight),
"bottom": Color(String(from["bottom"])).lerp(Color(String(to["bottom"])), weight),
"light": Color(String(from["light"])).lerp(Color(String(to["light"])), weight),
"stars": lerpf(float(from["stars"]), float(to["stars"]), weight),
}
var last: Dictionary = KEYFRAMES[KEYFRAMES.size() - 1]
return {
"top": Color(String(last["top"])),
"bottom": Color(String(last["bottom"])),
"light": Color(String(last["light"])),
"stars": float(last["stars"]),
}
## Доля пути солнца по небу: 0 — восход слева, 1 — закат справа.
## -1, если солнце под горизонтом.
static func sun_progress(hour: float) -> float:
var moment := fposmod(hour, 24.0)
if moment < SUNRISE or moment > SUNSET:
return -1.0
return (moment - SUNRISE) / (SUNSET - SUNRISE)
## То же для луны — она идёт по небу оставшуюся часть суток.
static func moon_progress(hour: float) -> float:
var moment := fposmod(hour, 24.0)
if moment > SUNRISE and moment < SUNSET:
return -1.0
var night_length := 24.0 - (SUNSET - SUNRISE)
var elapsed := moment - SUNSET if moment >= SUNSET else moment + (24.0 - SUNSET)
return elapsed / night_length
## Час суток дробным числом из словаря Time.
static func hour_of(moment: Dictionary) -> float:
return float(int(moment["hour"])) + float(int(moment["minute"])) / 60.0