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:
@@ -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 = "Убежище загружено."
|
||||
Reference in New Issue
Block a user