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
+242
View File
@@ -0,0 +1,242 @@
class_name VaultView
extends Node2D
## Отрисовка убежища в разрезе: небо, порода, лифтовая шахта, комнаты
## и призрак строительства.
##
## Ассетов у проекта пока нет, поэтому всё рисуется процедурно в _draw().
## Когда появится графика, заменять нужно только этот файл — модель
## (VaultGrid) и логика сцены от него не зависят.
const SKY_TOP := Color("#050912")
const SKY_HORIZON := Color("#16333f")
const DIRT_TOP := Color("#2a231d")
const DIRT_BOTTOM := Color("#100d0b")
const SURFACE := Color("#3d4f3a")
const SHELL := Color("#1b262c")
const WALL := Color("#2c3b45")
const OUTLINE := Color("#080d11")
const SHAFT := Color("#141c21")
const RUNG := Color("#c9a227", 0.45)
const CABIN := Color("#c9a227", 0.22)
const EMPTY_FILL := Color("#ffffff", 0.02)
const EMPTY_LINE := Color("#ffffff", 0.06)
const GHOST_OK := Color("#2ee6c5")
const GHOST_BAD := Color("#f2704a")
const MARGIN := 1200.0
const SKY_HEIGHT := 900.0
const DIRT_DEPTH := 460.0
const PEBBLE_SEED := 20260810
## Модель, которую рисуем. Ставится сценой сразу после создания.
var grid: VaultGrid
var _ghost_kind := ""
var _ghost_cell := Vector2i(-1, -1)
var _demolish := false
var _pebbles: Array[Dictionary] = []
func _ready() -> void:
_generate_pebbles()
## Подсветка под курсором: тип строящейся комнаты (пустая строка — ничего),
## ячейка и режим сноса.
func set_ghost(kind: String, cell: Vector2i, demolish: bool) -> void:
if kind == _ghost_kind and cell == _ghost_cell and demolish == _demolish:
return
_ghost_kind = kind
_ghost_cell = cell
_demolish = demolish
queue_redraw()
func _draw() -> void:
if grid == null:
return
_draw_sky()
_draw_dirt()
_draw_shell()
_draw_empty_cells()
_draw_shaft()
_draw_floor_numbers()
for room: Dictionary in grid.rooms:
_draw_room(room)
_draw_ghost()
# --- Фон --------------------------------------------------------------------
func _draw_sky() -> void:
var bounds := VaultGrid.bounds()
var left := -MARGIN
var right := bounds.size.x + MARGIN
_fill_gradient(Rect2(Vector2(left, -SKY_HEIGHT), Vector2(right - left, SKY_HEIGHT)),
SKY_TOP, SKY_HORIZON)
func _draw_dirt() -> void:
var bounds := VaultGrid.bounds()
var left := -MARGIN
var right := bounds.size.x + MARGIN
var depth := bounds.size.y + DIRT_DEPTH
_fill_gradient(Rect2(Vector2(left, 0.0), Vector2(right - left, depth)), DIRT_TOP, DIRT_BOTTOM)
for pebble: Dictionary in _pebbles:
draw_circle(pebble["position"], float(pebble["radius"]), pebble["color"])
# Полоса поверхности — граница земли и неба.
draw_line(Vector2(left, 0.0), Vector2(right, 0.0), SURFACE, 5.0)
## Заливка прямоугольника вертикальным градиентом: draw_rect умеет только
## сплошной цвет, поэтому идём через полигон с цветами вершин.
func _fill_gradient(rect: Rect2, top: Color, bottom: Color) -> void:
var points := PackedVector2Array([
rect.position,
Vector2(rect.end.x, rect.position.y),
rect.end,
Vector2(rect.position.x, rect.end.y),
])
draw_polygon(points, PackedColorArray([top, top, bottom, bottom]))
func _generate_pebbles() -> void:
var rng := RandomNumberGenerator.new()
rng.seed = PEBBLE_SEED
var bounds := VaultGrid.bounds()
for i in 260:
_pebbles.append({
"position": Vector2(
rng.randf_range(-MARGIN, bounds.size.x + MARGIN),
rng.randf_range(6.0, bounds.size.y + DIRT_DEPTH)
),
"radius": rng.randf_range(1.5, 5.0),
"color": Color("#000000", rng.randf_range(0.10, 0.28)),
})
# --- Убежище ----------------------------------------------------------------
func _draw_shell() -> void:
draw_rect(VaultGrid.bounds().grow(10.0), SHELL)
func _draw_empty_cells() -> void:
for a_floor in VaultGrid.FLOORS:
for column in range(VaultGrid.ELEVATOR_COLUMN + 1, VaultGrid.COLUMNS):
if grid.room_index_at(a_floor, column) >= 0:
continue
var rect := VaultGrid.cell_rect(a_floor, column).grow(-3.0)
draw_rect(rect, EMPTY_FILL)
draw_rect(rect, EMPTY_LINE, false, 1.0)
func _draw_shaft() -> void:
var rect := Rect2(
Vector2(VaultGrid.ELEVATOR_COLUMN * VaultGrid.CELL.x, 0.0),
Vector2(VaultGrid.CELL.x, VaultGrid.FLOORS * VaultGrid.CELL.y)
)
draw_rect(rect, SHAFT)
var y := 16.0
while y < rect.size.y:
draw_line(Vector2(rect.position.x + 18.0, y), Vector2(rect.end.x - 18.0, y), RUNG, 2.0)
y += 26.0
# Кабина стоит на верхнем этаже.
var cabin := Rect2(rect.position + Vector2(22.0, 14.0), Vector2(rect.size.x - 44.0, 92.0))
draw_rect(cabin, CABIN)
draw_rect(cabin, RUNG, false, 2.0)
draw_rect(rect, OUTLINE, false, 2.0)
func _draw_floor_numbers() -> void:
var font := ThemeDB.fallback_font
for a_floor in VaultGrid.FLOORS:
var pos := Vector2(-46.0, a_floor * VaultGrid.CELL.y + VaultGrid.CELL.y * 0.5 + 7.0)
draw_string(font, pos, str(a_floor + 1), HORIZONTAL_ALIGNMENT_LEFT, -1, 20,
Color("#ffffff", 0.28))
func _draw_room(room: Dictionary) -> void:
var rect := VaultGrid.room_rect(room)
var kind: Dictionary = VaultGrid.KINDS[String(room["kind"])]
var accent := Color(String(kind["color"]))
draw_rect(rect, WALL)
var inner := rect.grow(-7.0)
_fill_gradient(inner, accent.lerp(Color("#0b1116"), 0.58), accent.lerp(Color("#060a0d"), 0.86))
# Свет от потолочной лампы.
var lamp := Vector2(inner.position.x + inner.size.x * 0.5, inner.position.y + 2.0)
draw_polygon(
PackedVector2Array([
lamp + Vector2(-16.0, 0.0),
lamp + Vector2(16.0, 0.0),
Vector2(inner.end.x - 10.0, inner.end.y),
Vector2(inner.position.x + 10.0, inner.end.y),
]),
PackedColorArray([
Color(accent, 0.13), Color(accent, 0.13), Color(accent, 0.0), Color(accent, 0.0),
])
)
_draw_equipment(inner, accent, VaultGrid.kind_width(String(room["kind"])))
# Пол.
draw_rect(
Rect2(Vector2(inner.position.x, inner.end.y - 7.0), Vector2(inner.size.x, 7.0)),
accent.lerp(Color("#05080a"), 0.55)
)
draw_rect(rect, OUTLINE, false, 2.0)
draw_string(ThemeDB.fallback_font, rect.position + Vector2(14.0, 30.0),
String(kind["label"]), HORIZONTAL_ALIGNMENT_LEFT, rect.size.x - 20.0, 17,
Color("#e6f1f7", 0.92))
## Силуэты оборудования у пола — чтобы комнаты не выглядели пустыми коробками.
func _draw_equipment(inner: Rect2, accent: Color, width: int) -> void:
var body := accent.lerp(Color("#04070a"), 0.62)
var glow := Color(accent, 0.55)
var baseline := inner.end.y - 7.0
var count := 3 if width > 1 else 2
var step := inner.size.x / float(count + 1)
for i in range(1, count + 1):
var center_x := inner.position.x + step * i
var height := 26.0 + float((i * 13) % 22)
var machine := Rect2(Vector2(center_x - 17.0, baseline - height), Vector2(34.0, height))
draw_rect(machine, body)
draw_rect(Rect2(machine.position + Vector2(6.0, 6.0), Vector2(22.0, 4.0)), glow)
# --- Строительство ----------------------------------------------------------
func _draw_ghost() -> void:
if _ghost_cell.x < 0:
return
if _demolish:
var index := grid.room_index_at(_ghost_cell.y, _ghost_cell.x)
if index < 0:
return
var target := VaultGrid.room_rect(grid.rooms[index])
draw_rect(target, Color(GHOST_BAD, 0.22))
draw_rect(target, GHOST_BAD, false, 3.0)
return
if _ghost_kind.is_empty():
return
var width := VaultGrid.kind_width(_ghost_kind)
var rect := VaultGrid.cell_rect(_ghost_cell.y, _ghost_cell.x, width)
var allowed := grid.can_place(_ghost_kind, _ghost_cell.y, _ghost_cell.x)
var tint := GHOST_OK if allowed else GHOST_BAD
draw_rect(rect, Color(tint, 0.16))
draw_rect(rect, tint, false, 3.0)