Refactor game structure and update project settings for 2D gameplay. Removed the game stub scene, introduced a new vault scene, and organized game scripts into distinct files for grid management, rendering, and scene control. Updated input actions for camera movement and changed rendering method to Mobile for better performance.

This commit is contained in:
Leonid Pershin
2026-08-10 21:36:56 +03:00
parent adfbbbcec3
commit 044dde7b5f
17 changed files with 838 additions and 158 deletions
+183
View File
@@ -0,0 +1,183 @@
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 = "Убежище загружено."