Files
g-world/scripts/game/vault_scene.gd
T

184 lines
5.7 KiB
GDScript

extends Node2D
## Игровой слой: убежище в разрезе, вид сбоку.
##
## Связывает три части: модель (VaultGrid), отрисовку (VaultView) и HUD.
## Здесь же живёт контракт сохранения — сцена лежит в группе "persistent".
##
## Управление: ЛКМ — построить или снести, ПКМ/СКМ — тащить вид,
## колесо — зум, WASD и стрелки — прокрутка.
## Строки сводки ресурсов: ключ из VaultGrid.totals() → подпись и цвет.
const STAT_ROWS := {
"power": {"label": "Питание", "color": "#f2b134"},
"water": {"label": "Вода", "color": "#4aa8f2"},
"food": {"label": "Еда", "color": "#f2704a"},
}
const HINT := "ЛКМ — строить · ПКМ — тащить вид · колесо — зум"
@onready var _saves: SaveManagerService = get_node("/root/SaveManager")
@onready var _vault: VaultView = $View
@onready var _camera: VaultCamera = $Camera
@onready var _stats: HBoxContainer = $Hud/Root/TopBar/Stats
@onready var _tools: HBoxContainer = $Hud/Root/BottomAnchor/Row/BuildBar/Panel/Tools
@onready var _status: Label = $Hud/Root/BottomAnchor/Row/BuildBar/Panel/Status
var _grid := VaultGrid.new()
var _selected_kind := "living"
var _demolish := false
var _stat_labels := {}
func _ready() -> void:
_grid.reset_to_starter()
_vault.grid = _grid
add_to_group(SaveManagerService.PERSIST_GROUP)
_saves.begin_session(scene_file_path)
_build_stats()
_build_tools()
_refresh_stats()
_status.text = HINT
func _process(_delta: float) -> void:
_vault.set_ghost(_selected_kind, _cell_under_mouse(), _demolish)
func _unhandled_input(event: InputEvent) -> void:
if not (event is InputEventMouseButton):
return
var button := event as InputEventMouseButton
if button.button_index != MOUSE_BUTTON_LEFT or not button.pressed:
return
_apply_at(_cell_under_mouse())
get_viewport().set_input_as_handled()
# --- Строительство ----------------------------------------------------------
func _cell_under_mouse() -> Vector2i:
return VaultGrid.cell_at(_vault.get_local_mouse_position())
func _apply_at(cell: Vector2i) -> void:
if _demolish:
if _grid.remove_at(cell.y, cell.x):
_after_change("Комната снесена.")
else:
_status.text = "Здесь нечего сносить."
return
if _grid.place(_selected_kind, cell.y, cell.x):
_after_change("Построено: %s" % VaultGrid.KINDS[_selected_kind]["label"])
else:
_status.text = "Здесь строить нельзя: занято или вплотную к шахте."
func _after_change(message: String) -> void:
_vault.queue_redraw()
_refresh_stats()
_status.text = message
# --- HUD --------------------------------------------------------------------
func _build_stats() -> void:
for key: String in STAT_ROWS:
var row := VBoxContainer.new()
row.add_theme_constant_override("separation", 0)
var caption := Label.new()
caption.text = String(STAT_ROWS[key]["label"])
caption.add_theme_font_size_override("font_size", 14)
caption.add_theme_color_override("font_color", Color("#8fa5ba"))
row.add_child(caption)
var value := Label.new()
value.add_theme_font_size_override("font_size", 24)
value.add_theme_color_override("font_color", Color(String(STAT_ROWS[key]["color"])))
row.add_child(value)
_stat_labels[key] = value
_stats.add_child(row)
func _refresh_stats() -> void:
var totals := _grid.totals()
for key: String in _stat_labels:
var amount := int(totals[key])
var label: Label = _stat_labels[key]
label.text = "%+d" % amount
# Дефицит важнее оформления: красим в тревожный цвет, а не в цвет ресурса.
if amount < 0:
label.add_theme_color_override("font_color", Color("#f2704a"))
else:
label.add_theme_color_override("font_color", Color(String(STAT_ROWS[key]["color"])))
func _build_tools() -> void:
var group := ButtonGroup.new()
for kind: String in VaultGrid.KINDS:
var button := Button.new()
button.text = String(VaultGrid.KINDS[kind]["label"])
button.toggle_mode = true
button.button_group = group
button.add_theme_font_size_override("font_size", 18)
button.button_pressed = kind == _selected_kind
button.pressed.connect(_on_kind_selected.bind(kind))
_tools.add_child(button)
var separator := Control.new()
separator.custom_minimum_size.x = 20
_tools.add_child(separator)
var demolish := Button.new()
demolish.text = "Снести"
demolish.toggle_mode = true
demolish.button_group = group
demolish.add_theme_font_size_override("font_size", 18)
demolish.pressed.connect(_on_demolish_selected)
_tools.add_child(demolish)
func _on_kind_selected(kind: String) -> void:
_selected_kind = kind
_demolish = false
_status.text = HINT
func _on_demolish_selected() -> void:
_demolish = true
_status.text = "Режим сноса: кликните по комнате."
# --- Сохранение -------------------------------------------------------------
func save_data() -> Dictionary:
return {
"rooms": _grid.to_array(),
"camera": {
"x": _camera.position.x,
"y": _camera.position.y,
"zoom": _camera.zoom.x,
},
}
func load_data(data: Dictionary) -> void:
_grid.from_array(data.get("rooms", []))
var camera_state: Dictionary = data.get("camera", {})
if not camera_state.is_empty():
_camera.position = Vector2(
float(camera_state.get("x", 0.0)), float(camera_state.get("y", 0.0))
)
var level := float(camera_state.get("zoom", 1.0))
_camera.zoom = Vector2(level, level)
_vault.queue_redraw()
_refresh_stats()
_status.text = "Убежище загружено."