Подземелье: тёмная шахта (комнаты друг над другом) вместо телепорта
- Тёмные комнаты теперь одной колонкой = скрытая вертикальная шахта - Персонаж идёт к шахте на своём этаже и ПРОХОДИТ по ней вертикально на другой этаж - Движение (и горизонтальное, и по шахте) анимируется боевым walk_0 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2a629adf2c
commit
085cf3e5fa
@@ -26,9 +26,9 @@ D:\Godot_v4.7.1\Godot_v4.7.1-stable_mono_win64.exe
|
|||||||
Главное меню (`scenes/MainMenu.tscn`) ведёт на три сцены (назад в меню — `Esc`):
|
Главное меню (`scenes/MainMenu.tscn`) ведёт на три сцены (назад в меню — `Esc`):
|
||||||
|
|
||||||
1. **Подземелье** (`scenes/Dungeon.tscn`) — разрез убежища à la Fallout Shelter: сетка 6×5
|
1. **Подземелье** (`scenes/Dungeon.tscn`) — разрез убежища à la Fallout Shelter: сетка 6×5
|
||||||
комнат, **тёмные комнаты-телепорты** (по одной на этаж — персонаж заходит и
|
комнат, **тёмная шахта** (колонка тёмных комнат друг над другом = скрытая лестница;
|
||||||
переносится на другой этаж), **объекты** (фонари/свет) и **несколько персонажей**,
|
персонаж заходит и проходит по ней на другой этаж, анимация — боевой `walk_0`),
|
||||||
которые ходят по этажам (нативные сцены, `walk_0`/`idle_0`).
|
**объекты** (фонари/свет) и **несколько персонажей** на этажах.
|
||||||
ЛКМ по персонажу — выбрать/тащить (перенос в комнату), ЛКМ по фону/WASD — панорама,
|
ЛКМ по персонажу — выбрать/тащить (перенос в комнату), ЛКМ по фону/WASD — панорама,
|
||||||
колесо — зум, `R` — сброс.
|
колесо — зум, `R` — сброс.
|
||||||
2. **Просмотр спрайтов** (`scenes/SpriteViewer.tscn`) — галерея вытащенных изображений
|
2. **Просмотр спрайтов** (`scenes/SpriteViewer.tscn`) — галерея вытащенных изображений
|
||||||
|
|||||||
+42
-33
@@ -20,7 +20,7 @@ public partial class RoomMap : Node2D
|
|||||||
private Vector2 _homePos;
|
private Vector2 _homePos;
|
||||||
|
|
||||||
private static float FloorY(int row) => row * Cell + Cell * 0.9f;
|
private static float FloorY(int row) => row * Cell + Cell * 0.9f;
|
||||||
private float[] _darkX; // X центра тёмной комнаты-телепорта на каждом этаже
|
private float _shaftX; // X тёмной шахты (комнаты друг над другом = скрытая лестница)
|
||||||
|
|
||||||
private readonly List<Pawn> _pawns = new();
|
private readonly List<Pawn> _pawns = new();
|
||||||
private System.Random _rng;
|
private System.Random _rng;
|
||||||
@@ -30,15 +30,15 @@ public partial class RoomMap : Node2D
|
|||||||
private PanelContainer _infoPanel;
|
private PanelContainer _infoPanel;
|
||||||
private Label _infoLabel;
|
private Label _infoLabel;
|
||||||
|
|
||||||
private enum PState { Idle, Walk, GoDark, Held }
|
private enum PState { Idle, Walk, GoShaft, Climb, Held }
|
||||||
|
|
||||||
private class Pawn
|
private class Pawn
|
||||||
{
|
{
|
||||||
public Node2D Node;
|
public Node2D Node;
|
||||||
public AnimationPlayer Ap;
|
public AnimationPlayer Ap;
|
||||||
public string Name;
|
public string Name;
|
||||||
public int Row;
|
public int Row, TargetRow;
|
||||||
public float X, TargetX, Speed, MinX, MaxX, IdleTimer;
|
public float X, TargetX, TargetY, Speed, MinX, MaxX, IdleTimer;
|
||||||
public PState State;
|
public PState State;
|
||||||
public string WalkAnim, IdleAnim;
|
public string WalkAnim, IdleAnim;
|
||||||
}
|
}
|
||||||
@@ -118,21 +118,19 @@ public partial class RoomMap : Node2D
|
|||||||
BuildPawns();
|
BuildPawns();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- тёмные комнаты-телепорты (по одной на этаж) ----------
|
// ---------- тёмная шахта: колонка тёмных комнат друг над другом (скрытая лестница) ----------
|
||||||
private void BuildDarkRooms()
|
private void BuildDarkRooms()
|
||||||
{
|
{
|
||||||
int[] cols = { 5, 0, 5, 0, 5 }; // столбец тёмной комнаты для каждого этажа (в шахматку по бокам)
|
const int col = 5; // одна колонка на всю высоту
|
||||||
_darkX = new float[Rows];
|
_shaftX = col * Cell + Cell * 0.5f;
|
||||||
for (int r = 0; r < Rows; r++)
|
for (int r = 0; r < Rows; r++)
|
||||||
{
|
{
|
||||||
int c = cols[r % cols.Length];
|
|
||||||
_darkX[r] = c * Cell + Cell * 0.5f;
|
|
||||||
// затемнение интерьера ячейки
|
// затемнение интерьера ячейки
|
||||||
AddRect(new Rect2(c * Cell + 8, r * Cell + 8, Cell - 16, Cell - 16), new Color(0.02f, 0.02f, 0.05f, 0.93f));
|
AddRect(new Rect2(col * Cell + 8, r * Cell + 8, Cell - 16, Cell - 16), new Color(0.02f, 0.02f, 0.05f, 0.94f));
|
||||||
// портальное свечение по центру
|
// слабое свечение по центру — вход в шахту
|
||||||
AddTex("res://assets/room_sliced/Light.png",
|
AddTex("res://assets/room_sliced/Light.png",
|
||||||
new Rect2(c * Cell + Cell * 0.28f, r * Cell + Cell * 0.28f, Cell * 0.44f, Cell * 0.44f),
|
new Rect2(col * Cell + Cell * 0.3f, r * Cell + Cell * 0.3f, Cell * 0.4f, Cell * 0.4f),
|
||||||
_world, new Color(0.5f, 0.4f, 1f, 0.55f));
|
_world, new Color(0.45f, 0.38f, 0.9f, 0.4f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,13 +212,13 @@ public partial class RoomMap : Node2D
|
|||||||
private void PlayWalk(Pawn p) { if (p.Ap != null && p.WalkAnim != null) p.Ap.Play(p.WalkAnim); }
|
private void PlayWalk(Pawn p) { if (p.Ap != null && p.WalkAnim != null) p.Ap.Play(p.WalkAnim); }
|
||||||
private void PlayIdle(Pawn p) { if (p.Ap != null && p.IdleAnim != null) p.Ap.Play(p.IdleAnim); }
|
private void PlayIdle(Pawn p) { if (p.Ap != null && p.IdleAnim != null) p.Ap.Play(p.IdleAnim); }
|
||||||
|
|
||||||
// решить, что делать после простоя: гулять по этажу или уйти в тёмную комнату (телепорт)
|
// решить: гулять по этажу или уйти в тёмную шахту и перейти на другой этаж
|
||||||
private void Decide(Pawn p)
|
private void Decide(Pawn p)
|
||||||
{
|
{
|
||||||
if (Rows > 1 && _rng.NextDouble() < 0.45)
|
if (Rows > 1 && _rng.NextDouble() < 0.45)
|
||||||
{
|
{
|
||||||
p.TargetX = _darkX[p.Row];
|
p.TargetX = _shaftX;
|
||||||
p.State = PState.GoDark;
|
p.State = PState.GoShaft;
|
||||||
PlayWalk(p);
|
PlayWalk(p);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -241,7 +239,7 @@ public partial class RoomMap : Node2D
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PState.Walk:
|
case PState.Walk:
|
||||||
case PState.GoDark:
|
case PState.GoShaft:
|
||||||
{
|
{
|
||||||
float d = Mathf.Sign(p.TargetX - p.X);
|
float d = Mathf.Sign(p.TargetX - p.X);
|
||||||
p.X += d * p.Speed * dt;
|
p.X += d * p.Speed * dt;
|
||||||
@@ -249,12 +247,37 @@ public partial class RoomMap : Node2D
|
|||||||
p.Node.Position = new Vector2(p.X, FloorY(p.Row));
|
p.Node.Position = new Vector2(p.X, FloorY(p.Row));
|
||||||
if (Mathf.Abs(p.TargetX - p.X) < 4f)
|
if (Mathf.Abs(p.TargetX - p.X) < 4f)
|
||||||
{
|
{
|
||||||
if (p.State == PState.GoDark) Teleport(p);
|
if (p.State == PState.GoShaft)
|
||||||
|
{
|
||||||
|
p.X = _shaftX;
|
||||||
|
do { p.TargetRow = _rng.Next(Rows); } while (p.TargetRow == p.Row);
|
||||||
|
p.TargetY = FloorY(p.TargetRow);
|
||||||
|
p.State = PState.Climb;
|
||||||
|
PlayWalk(p); // движение по шахте — боевой walk
|
||||||
|
}
|
||||||
else { p.State = PState.Idle; p.IdleTimer = 0.8f + (float)_rng.NextDouble() * 2.2f; PlayIdle(p); }
|
else { p.State = PState.Idle; p.IdleTimer = 0.8f + (float)_rng.NextDouble() * 2.2f; PlayIdle(p); }
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case PState.Climb: // вертикальное движение сквозь тёмную шахту
|
||||||
|
{
|
||||||
|
float cy = p.Node.Position.Y;
|
||||||
|
cy += Mathf.Sign(p.TargetY - cy) * p.Speed * dt;
|
||||||
|
p.Node.Position = new Vector2(_shaftX, cy);
|
||||||
|
p.Node.Scale = new Vector2(1f, 1f);
|
||||||
|
if (Mathf.Abs(p.TargetY - cy) < 4f)
|
||||||
|
{
|
||||||
|
p.Row = p.TargetRow;
|
||||||
|
p.Node.Position = new Vector2(_shaftX, FloorY(p.Row));
|
||||||
|
p.State = PState.Idle;
|
||||||
|
p.IdleTimer = 0.4f + (float)_rng.NextDouble() * 1.5f;
|
||||||
|
PlayIdle(p);
|
||||||
|
if (_selected == p) ShowInfo(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case PState.Idle:
|
case PState.Idle:
|
||||||
p.IdleTimer -= dt;
|
p.IdleTimer -= dt;
|
||||||
if (p.IdleTimer <= 0f) Decide(p);
|
if (p.IdleTimer <= 0f) Decide(p);
|
||||||
@@ -263,20 +286,6 @@ public partial class RoomMap : Node2D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// телепорт: из тёмной комнаты своего этажа — в тёмную комнату случайного другого этажа
|
|
||||||
private void Teleport(Pawn p)
|
|
||||||
{
|
|
||||||
int dest = p.Row;
|
|
||||||
if (Rows > 1) do { dest = _rng.Next(Rows); } while (dest == p.Row);
|
|
||||||
p.Row = dest;
|
|
||||||
p.X = _darkX[dest];
|
|
||||||
p.Node.Position = new Vector2(p.X, FloorY(dest));
|
|
||||||
p.State = PState.Idle;
|
|
||||||
p.IdleTimer = 0.5f + (float)_rng.NextDouble() * 1.2f;
|
|
||||||
PlayIdle(p);
|
|
||||||
if (_selected == p) ShowInfo(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Pawn PawnAt(Vector2 worldPos)
|
private Pawn PawnAt(Vector2 worldPos)
|
||||||
{
|
{
|
||||||
float w = Cell * 0.5f, h = Cell * 0.85f;
|
float w = Cell * 0.5f, h = Cell * 0.85f;
|
||||||
@@ -347,7 +356,7 @@ public partial class RoomMap : Node2D
|
|||||||
private void UpdateLabel()
|
private void UpdateLabel()
|
||||||
{
|
{
|
||||||
_label.Text =
|
_label.Text =
|
||||||
$"Карта убежища — {Cols}×{Rows} комнат, тёмные комнаты-телепорты, {_pawns.Count} персонажа\n" +
|
$"Карта убежища — {Cols}×{Rows} комнат, тёмная шахта (скрытая лестница), {_pawns.Count} персонажа\n" +
|
||||||
$"ЛКМ по персонажу — выбрать/тащить · ЛКМ по фону/WASD — панорама · колесо — зум · R — сброс · Esc — меню";
|
$"ЛКМ по персонажу — выбрать/тащить · ЛКМ по фону/WASD — панорама · колесо — зум · R — сброс · Esc — меню";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user