116 lines
3.8 KiB
GDScript
116 lines
3.8 KiB
GDScript
class_name SkyView
|
|
extends Node2D
|
|
## Небо над убежищем: градиент по времени суток, звёзды, солнце и луна.
|
|
##
|
|
## Рисуется первым, за пейзажем и породой. Что рисовать — решает SkyCycle,
|
|
## насколько это видно сквозь облака — WeatherSystem.
|
|
|
|
const SUN_TEXTURE := preload("res://background/PNG/sun.png")
|
|
const MOON_TEXTURE := preload("res://background/PNG/moon_full.png")
|
|
|
|
## Небо начинается здесь и идёт до уровня земли (y = 0).
|
|
const TOP := -1700.0
|
|
const LEFT := -1600.0
|
|
const RIGHT := 2900.0
|
|
|
|
## Дуга, по которой идут светила.
|
|
const ARC_RADIUS := Vector2(900.0, 620.0)
|
|
const ARC_BASE := -40.0
|
|
|
|
const STAR_COUNT := 240
|
|
const STAR_SEED := 20120401
|
|
|
|
## Час суток; сцена обновляет его вслед за часами.
|
|
var hour := 6.0
|
|
## Плотность облаков 0..1 — сквозь них хуже видно звёзды и светила.
|
|
var clouds := 0.0
|
|
|
|
var _stars: Array[Dictionary] = []
|
|
|
|
|
|
func _ready() -> void:
|
|
_generate_stars()
|
|
|
|
|
|
## Одним вызовом — чтобы не гонять перерисовку дважды.
|
|
func set_conditions(hour_of_day: float, cloudiness: float) -> void:
|
|
hour = hour_of_day
|
|
clouds = cloudiness
|
|
queue_redraw()
|
|
|
|
|
|
func _draw() -> void:
|
|
var sky := SkyCycle.sample(hour)
|
|
_draw_gradient(sky)
|
|
_draw_stars(float(sky["stars"]))
|
|
_draw_bodies()
|
|
|
|
|
|
func _draw_gradient(sky: Dictionary) -> void:
|
|
var points := PackedVector2Array([
|
|
Vector2(LEFT, TOP), Vector2(RIGHT, TOP), Vector2(RIGHT, 0.0), Vector2(LEFT, 0.0),
|
|
])
|
|
var top: Color = sky["top"]
|
|
var bottom: Color = sky["bottom"]
|
|
draw_polygon(points, PackedColorArray([top, top, bottom, bottom]))
|
|
|
|
|
|
func _draw_stars(brightness: float) -> void:
|
|
# Плотная облачность гасит звёзды почти полностью.
|
|
var visibility := brightness * (1.0 - clampf(clouds, 0.0, 1.0) * 0.9)
|
|
if visibility <= 0.01:
|
|
return
|
|
|
|
for star: Dictionary in _stars:
|
|
var alpha: float = float(star["alpha"]) * visibility
|
|
draw_circle(star["position"], float(star["radius"]), Color(star["tint"], alpha))
|
|
|
|
|
|
func _draw_bodies() -> void:
|
|
# Сквозь облака светило просвечивает, но тускло.
|
|
var through := 1.0 - clampf(clouds, 0.0, 1.0) * 0.75
|
|
|
|
var sun := SkyCycle.sun_progress(hour)
|
|
if sun >= 0.0:
|
|
var position := _arc_position(sun)
|
|
draw_circle(position, 150.0, Color("#ffd27a", 0.10 * through))
|
|
draw_circle(position, 92.0, Color("#ffdc93", 0.14 * through))
|
|
_draw_body(SUN_TEXTURE, position, 1.7, Color(1.0, 1.0, 1.0, through))
|
|
return
|
|
|
|
var moon := SkyCycle.moon_progress(hour)
|
|
if moon >= 0.0:
|
|
var position := _arc_position(moon)
|
|
draw_circle(position, 110.0, Color("#cfe0ff", 0.07 * through))
|
|
_draw_body(MOON_TEXTURE, position, 1.35, Color(1.0, 1.0, 1.0, through))
|
|
|
|
|
|
func _draw_body(texture: Texture2D, position: Vector2, scale: float, tint: Color) -> void:
|
|
var size := Vector2(texture.get_size()) * scale
|
|
draw_texture_rect(texture, Rect2(position - size * 0.5, size), false, tint)
|
|
|
|
|
|
## Точка на дуге: 0 — у левого горизонта, 1 — у правого.
|
|
func _arc_position(progress: float) -> Vector2:
|
|
var angle := PI * (1.0 - progress)
|
|
var center_x := VaultGrid.bounds().get_center().x
|
|
return Vector2(
|
|
center_x + cos(angle) * ARC_RADIUS.x,
|
|
ARC_BASE - sin(angle) * ARC_RADIUS.y
|
|
)
|
|
|
|
|
|
func _generate_stars() -> void:
|
|
var rng := RandomNumberGenerator.new()
|
|
rng.seed = STAR_SEED
|
|
|
|
for index in STAR_COUNT:
|
|
_stars.append({
|
|
"position": Vector2(
|
|
rng.randf_range(LEFT, RIGHT), rng.randf_range(TOP, -140.0)
|
|
),
|
|
"radius": rng.randf_range(1.4, 3.6),
|
|
"alpha": rng.randf_range(0.35, 1.0),
|
|
"tint": Color("#bcd2ff").lerp(Color("#fff2d8"), rng.randf()),
|
|
})
|