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()), })