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,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)
|
||||
Reference in New Issue
Block a user