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