121 lines
4.2 KiB
GDScript
121 lines
4.2 KiB
GDScript
class_name WeatherIcon
|
|
extends Control
|
|
## Значок погоды для HUD.
|
|
##
|
|
## Рисуется процедурно: иконок в наборе фона нет, а тащить шрифт с символами
|
|
## ради семи состояний неоправданно. Заодно значок красится темой, а не
|
|
## растром, и одинаково чёткий на любом масштабе.
|
|
|
|
const SUN := Color("#f2b134")
|
|
const MOON := Color("#cfd8e6")
|
|
const CLOUD := Color("#c6d4e0")
|
|
const CLOUD_DARK := Color("#8fa5ba")
|
|
const RAIN := Color("#4aa8f2")
|
|
const SNOW := Color("#e6f1f7")
|
|
const BOLT := Color("#f2b134")
|
|
|
|
## Тип погоды из WeatherSystem.Kind.
|
|
var kind := 0
|
|
## Ночью в ясную погоду вместо солнца показываем луну.
|
|
var night := false
|
|
|
|
|
|
func _ready() -> void:
|
|
custom_minimum_size = Vector2(24.0, 24.0)
|
|
|
|
|
|
func set_state(weather_kind: int, is_night: bool) -> void:
|
|
if weather_kind == kind and is_night == night:
|
|
return
|
|
kind = weather_kind
|
|
night = is_night
|
|
queue_redraw()
|
|
|
|
|
|
func _draw() -> void:
|
|
var box := Rect2(Vector2.ZERO, size)
|
|
var center := box.get_center()
|
|
|
|
match kind:
|
|
WeatherSystem.Kind.CLEAR:
|
|
_draw_body(center, size.x * 0.30)
|
|
WeatherSystem.Kind.CLOUDY:
|
|
_draw_body(center - Vector2(size.x * 0.14, size.y * 0.14), size.x * 0.22)
|
|
_draw_cloud(center + Vector2(size.x * 0.06, size.y * 0.10), CLOUD)
|
|
WeatherSystem.Kind.OVERCAST:
|
|
_draw_cloud(center - Vector2(size.x * 0.10, size.y * 0.06), CLOUD_DARK)
|
|
_draw_cloud(center + Vector2(size.x * 0.08, size.y * 0.08), CLOUD)
|
|
WeatherSystem.Kind.RAIN:
|
|
_draw_cloud(center - Vector2(0.0, size.y * 0.14), CLOUD)
|
|
_draw_streaks(center, RAIN)
|
|
WeatherSystem.Kind.STORM:
|
|
_draw_cloud(center - Vector2(0.0, size.y * 0.14), CLOUD_DARK)
|
|
_draw_streaks(center, RAIN)
|
|
_draw_bolt(center)
|
|
WeatherSystem.Kind.FOG:
|
|
_draw_fog(box)
|
|
WeatherSystem.Kind.SNOW:
|
|
_draw_cloud(center - Vector2(0.0, size.y * 0.14), CLOUD)
|
|
_draw_flakes(center)
|
|
|
|
|
|
## Солнце или луна — смотря какое время суток.
|
|
func _draw_body(center: Vector2, radius: float) -> void:
|
|
if night:
|
|
# Полумесяц: круг с вырезом, вырез закрашен фоном значка.
|
|
draw_circle(center, radius, MOON)
|
|
draw_circle(center + Vector2(radius * 0.55, -radius * 0.30), radius * 0.92, Color(0, 0, 0, 0))
|
|
draw_arc(center, radius, PI * 0.35, PI * 1.65, 20, MOON, 2.0)
|
|
return
|
|
|
|
draw_circle(center, radius, SUN)
|
|
for index in 8:
|
|
var angle := TAU * float(index) / 8.0
|
|
var direction := Vector2(cos(angle), sin(angle))
|
|
draw_line(center + direction * (radius * 1.35), center + direction * (radius * 1.85), SUN, 1.6)
|
|
|
|
|
|
func _draw_cloud(center: Vector2, tint: Color) -> void:
|
|
var unit := size.x * 0.12
|
|
draw_circle(center + Vector2(-unit * 1.1, 0.0), unit * 1.05, tint)
|
|
draw_circle(center + Vector2(unit * 1.1, unit * 0.15), unit * 0.9, tint)
|
|
draw_circle(center + Vector2(0.0, -unit * 0.55), unit * 1.25, tint)
|
|
draw_rect(Rect2(center + Vector2(-unit * 1.9, -unit * 0.1), Vector2(unit * 3.8, unit * 1.1)), tint)
|
|
|
|
|
|
func _draw_streaks(center: Vector2, tint: Color) -> void:
|
|
var unit := size.x * 0.12
|
|
for index in 3:
|
|
var start := center + Vector2((float(index) - 1.0) * unit * 1.4, unit * 1.3)
|
|
draw_line(start, start + Vector2(-unit * 0.35, unit * 1.3), tint, 1.8)
|
|
|
|
|
|
func _draw_flakes(center: Vector2) -> void:
|
|
var unit := size.x * 0.12
|
|
for index in 3:
|
|
draw_circle(center + Vector2((float(index) - 1.0) * unit * 1.4, unit * 1.9), unit * 0.32, SNOW)
|
|
|
|
|
|
func _draw_bolt(center: Vector2) -> void:
|
|
var unit := size.x * 0.12
|
|
draw_polygon(
|
|
PackedVector2Array([
|
|
center + Vector2(unit * 0.2, unit * 1.1),
|
|
center + Vector2(unit * 1.2, unit * 1.1),
|
|
center + Vector2(unit * 0.4, unit * 2.6),
|
|
center + Vector2(unit * 0.7, unit * 1.7),
|
|
center + Vector2(-unit * 0.2, unit * 1.7),
|
|
]),
|
|
PackedColorArray([BOLT, BOLT, BOLT, BOLT, BOLT])
|
|
)
|
|
|
|
|
|
func _draw_fog(box: Rect2) -> void:
|
|
for index in 3:
|
|
var y := box.position.y + box.size.y * (0.32 + float(index) * 0.18)
|
|
var inset := box.size.x * (0.08 + float(index % 2) * 0.12)
|
|
draw_line(
|
|
Vector2(box.position.x + inset, y), Vector2(box.end.x - inset, y),
|
|
CLOUD_DARK, 2.0
|
|
)
|