extends Node ## 실제 시계에 맞춰 바다의 빛을 바꾼다. ## ## 게임 안의 시간을 따로 돌리지 않고 바깥 시각을 그대로 쓴다. ## 이 위젯은 하루 종일 화면 아래에 켜져 있는 물건이라, 밤에 켰는데 바다가 한낮이면 ## 오히려 어색하다. 새벽에 일하면 바다도 새벽이어야 창밖처럼 읽힌다. ## ## 이름(새벽/아침/낮/저녁/밤)은 구간으로 끊지만 빛은 끊지 않는다. ## 색과 밝기는 시각 사이를 계속 보간해서, 해가 지는 동안 서서히 물든다. ## 이름이 바뀐 순간에만 나온다. 색이 바뀔 때마다 나오지는 않는다. signal phase_changed(phase_name: String) ## 구간의 시작 시각. 마지막(밤)은 자정을 넘겨 다음 새벽까지 이어진다. const PHASES := [ {"hour": 4.0, "name": "새벽"}, {"hour": 6.5, "name": "아침"}, {"hour": 10.0, "name": "낮"}, {"hour": 17.0, "name": "저녁"}, {"hour": 20.0, "name": "밤"}, ] ## 하루의 빛. 사이 시각은 이 표를 보간해서 만든다. ## tint : 바다 전체에 곱하는 색. 흰색이면 한낮 그대로. ## light: 수면에서 내려오는 빛의 양. 물결 무늬와 빛줄기의 세기가 여기 붙는다. const LIGHT_KEYS := [ {"hour": 0.0, "tint": Color(0.26, 0.33, 0.62), "light": 0.08}, {"hour": 4.0, "tint": Color(0.48, 0.44, 0.80), "light": 0.18}, {"hour": 6.0, "tint": Color(0.88, 0.68, 0.74), "light": 0.42}, {"hour": 7.5, "tint": Color(1.00, 0.87, 0.73), "light": 0.72}, {"hour": 11.0, "tint": Color(1.00, 1.00, 1.00), "light": 1.00}, {"hour": 16.0, "tint": Color(1.00, 0.98, 0.92), "light": 0.95}, {"hour": 18.5, "tint": Color(1.00, 0.72, 0.50), "light": 0.55}, {"hour": 20.5, "tint": Color(0.44, 0.44, 0.72), "light": 0.20}, {"hour": 24.0, "tint": Color(0.26, 0.33, 0.62), "light": 0.08}, ] ## 빛은 천천히 변하므로 매 프레임 다시 잴 이유가 없다. const REFRESH_INTERVAL := 0.5 ## 0 이상이면 그 시각으로 고정한다. 테스트와 눈으로 확인할 때 쓴다. var forced_hour := -1.0: set(value): forced_hour = value refresh() var tint := Color.WHITE var light := 1.0 var phase := "" var _timer := 0.0 func _ready() -> void: # 개발 중 특정 시각을 눈으로 확인할 때: godot --path . -- --hour=21 for arg in OS.get_cmdline_user_args(): if arg.begins_with("--hour="): forced_hour = float(arg.trim_prefix("--hour=")) refresh() func _process(delta: float) -> void: _timer += delta if _timer < REFRESH_INTERVAL: return _timer = 0.0 refresh() ## 지금 몇 시인지. 소수점까지 있는 시각(13.5 = 오후 1시 30분). func hour() -> float: if forced_hour >= 0.0: return fposmod(forced_hour, 24.0) var t := Time.get_time_dict_from_system() return float(t.hour) + float(t.minute) / 60.0 + float(t.second) / 3600.0 func refresh() -> void: var h := hour() tint = tint_at(h) light = light_at(h) var next_phase := phase_at(h) if next_phase != phase: phase = next_phase phase_changed.emit(phase) ## 그 시각이 어느 구간인지. 자정부터 첫 구간 전까지는 전날 밤이 이어진다. func phase_at(h: float) -> String: var found := String(PHASES[PHASES.size() - 1].name) for p in PHASES: if h >= float(p.hour): found = String(p.name) return found func tint_at(h: float) -> Color: var b := _bounds(h) return Color(LIGHT_KEYS[b[0]].tint).lerp(LIGHT_KEYS[b[1]].tint, b[2]) func light_at(h: float) -> float: var b := _bounds(h) return lerpf(float(LIGHT_KEYS[b[0]].light), float(LIGHT_KEYS[b[1]].light), b[2]) ## 그 시각을 감싸는 두 열쇠와 사이 비율. [앞, 뒤, 0~1] func _bounds(h: float) -> Array: var t := clampf(h, 0.0, 24.0) for i in range(LIGHT_KEYS.size() - 1): var a := float(LIGHT_KEYS[i].hour) var b := float(LIGHT_KEYS[i + 1].hour) if t <= b: return [i, i + 1, inverse_lerp(a, b, maxf(t, a))] var last := LIGHT_KEYS.size() - 1 return [last, last, 0.0]