diff --git a/README.md b/README.md index c3ec2c9..5ae7a4b 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ D:\Godot_v4.7.1\Godot_v4.7.1-stable_mono_win64.exe Главное меню (`scenes/MainMenu.tscn`) ведёт на три сцены (назад в меню — `Esc`): 1. **Подземелье** (`scenes/Dungeon.tscn`) — разрез убежища à la Fallout Shelter: сетка 6×5 - комнат, **тёмные комнаты-телепорты** (по одной на этаж — персонаж заходит и - переносится на другой этаж), **объекты** (фонари/свет) и **несколько персонажей**, - которые ходят по этажам (нативные сцены, `walk_0`/`idle_0`). + комнат, **тёмная шахта** (колонка тёмных комнат друг над другом = скрытая лестница; + персонаж заходит и проходит по ней на другой этаж, анимация — боевой `walk_0`), + **объекты** (фонари/свет) и **несколько персонажей** на этажах. ЛКМ по персонажу — выбрать/тащить (перенос в комнату), ЛКМ по фону/WASD — панорама, колесо — зум, `R` — сброс. 2. **Просмотр спрайтов** (`scenes/SpriteViewer.tscn`) — галерея вытащенных изображений diff --git a/src/RoomMap.cs b/src/RoomMap.cs index e740581..5f76fc2 100644 --- a/src/RoomMap.cs +++ b/src/RoomMap.cs @@ -20,7 +20,7 @@ public partial class RoomMap : Node2D private Vector2 _homePos; private static float FloorY(int row) => row * Cell + Cell * 0.9f; - private float[] _darkX; // X центра тёмной комнаты-телепорта на каждом этаже + private float _shaftX; // X тёмной шахты (комнаты друг над другом = скрытая лестница) private readonly List _pawns = new(); private System.Random _rng; @@ -30,15 +30,15 @@ public partial class RoomMap : Node2D private PanelContainer _infoPanel; private Label _infoLabel; - private enum PState { Idle, Walk, GoDark, Held } + private enum PState { Idle, Walk, GoShaft, Climb, Held } private class Pawn { public Node2D Node; public AnimationPlayer Ap; public string Name; - public int Row; - public float X, TargetX, Speed, MinX, MaxX, IdleTimer; + public int Row, TargetRow; + public float X, TargetX, TargetY, Speed, MinX, MaxX, IdleTimer; public PState State; public string WalkAnim, IdleAnim; } @@ -118,21 +118,19 @@ public partial class RoomMap : Node2D BuildPawns(); } - // ---------- тёмные комнаты-телепорты (по одной на этаж) ---------- + // ---------- тёмная шахта: колонка тёмных комнат друг над другом (скрытая лестница) ---------- private void BuildDarkRooms() { - int[] cols = { 5, 0, 5, 0, 5 }; // столбец тёмной комнаты для каждого этажа (в шахматку по бокам) - _darkX = new float[Rows]; + const int col = 5; // одна колонка на всю высоту + _shaftX = col * Cell + Cell * 0.5f; 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", - new Rect2(c * Cell + Cell * 0.28f, r * Cell + Cell * 0.28f, Cell * 0.44f, Cell * 0.44f), - _world, new Color(0.5f, 0.4f, 1f, 0.55f)); + new Rect2(col * Cell + Cell * 0.3f, r * Cell + Cell * 0.3f, Cell * 0.4f, Cell * 0.4f), + _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 PlayIdle(Pawn p) { if (p.Ap != null && p.IdleAnim != null) p.Ap.Play(p.IdleAnim); } - // решить, что делать после простоя: гулять по этажу или уйти в тёмную комнату (телепорт) + // решить: гулять по этажу или уйти в тёмную шахту и перейти на другой этаж private void Decide(Pawn p) { if (Rows > 1 && _rng.NextDouble() < 0.45) { - p.TargetX = _darkX[p.Row]; - p.State = PState.GoDark; + p.TargetX = _shaftX; + p.State = PState.GoShaft; PlayWalk(p); } else @@ -241,7 +239,7 @@ public partial class RoomMap : Node2D break; case PState.Walk: - case PState.GoDark: + case PState.GoShaft: { float d = Mathf.Sign(p.TargetX - p.X); 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)); 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); } } 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: p.IdleTimer -= dt; 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) { float w = Cell * 0.5f, h = Cell * 0.85f; @@ -347,7 +356,7 @@ public partial class RoomMap : Node2D private void UpdateLabel() { _label.Text = - $"Карта убежища — {Cols}×{Rows} комнат, тёмные комнаты-телепорты, {_pawns.Count} персонажа\n" + + $"Карта убежища — {Cols}×{Rows} комнат, тёмная шахта (скрытая лестница), {_pawns.Count} персонажа\n" + $"ЛКМ по персонажу — выбрать/тащить · ЛКМ по фону/WASD — панорама · колесо — зум · R — сброс · Esc — меню"; }