Подземелье: лестницы, объекты и гуляющие персонажи
- Процедурные лестницы-шахты между этажами - Объекты в комнатах (фонари Lantern, свечение Light) - 5 нативных персонажей патрулируют этажи (walk_0/idle_0, разворот, простое блуждание) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a0e08cf146
commit
b048a83966
@@ -26,7 +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
|
||||||
комнат. ЛКМ/WASD — панорама, колесо — зум, `R` — сброс.
|
комнат, **лестницы** между этажами, **объекты** (фонари/свет) и **несколько персонажей**,
|
||||||
|
которые ходят по этажам (нативные сцены с анимацией `walk_0`/`idle_0`).
|
||||||
|
ЛКМ/WASD — панорама, колесо — зум, `R` — сброс.
|
||||||
2. **Просмотр спрайтов** (`scenes/SpriteViewer.tscn`) — галерея вытащенных изображений
|
2. **Просмотр спрайтов** (`scenes/SpriteViewer.tscn`) — галерея вытащенных изображений
|
||||||
(UI, фоны, эффекты, нарезанные спрайты). `A/D` — картинка, `W/S` — категория, колесо — зум.
|
(UI, фоны, эффекты, нарезанные спрайты). `A/D` — картинка, `W/S` — категория, колесо — зум.
|
||||||
3. **Нативные анимации** (`scenes/NativeViewer.tscn`) — браузер всех 38 персонажей нативно:
|
3. **Нативные анимации** (`scenes/NativeViewer.tscn`) — браузер всех 38 персонажей нативно:
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ config/icon="res://icon.svg"
|
|||||||
|
|
||||||
project/assembly_name="ProjectRR"
|
project/assembly_name="ProjectRR"
|
||||||
|
|
||||||
|
[editor]
|
||||||
|
|
||||||
|
version_control/plugin_name="GitPlugin"
|
||||||
|
version_control/autoload_on_startup=true
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
3d/physics_engine="Jolt Physics"
|
3d/physics_engine="Jolt Physics"
|
||||||
|
|||||||
+156
-2
@@ -1,6 +1,8 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
// Демо-карта «убежища» в разрезе (à la Fallout Shelter): сетка комнат из игровых текстур.
|
// Демо-карта «убежища» в разрезе (à la Fallout Shelter): комнаты, лестницы, объекты
|
||||||
|
// и несколько персонажей, гуляющих по этажам.
|
||||||
// ЛКМ-перетаскивание или WASD/стрелки — панорама
|
// ЛКМ-перетаскивание или WASD/стрелки — панорама
|
||||||
// колесо мыши — зум, R — сброс вида
|
// колесо мыши — зум, R — сброс вида
|
||||||
public partial class RoomMap : Node2D
|
public partial class RoomMap : Node2D
|
||||||
@@ -8,6 +10,8 @@ public partial class RoomMap : Node2D
|
|||||||
private const float Cell = 256f;
|
private const float Cell = 256f;
|
||||||
private const int Cols = 6;
|
private const int Cols = 6;
|
||||||
private const int Rows = 5;
|
private const int Rows = 5;
|
||||||
|
private const float CharScale = 0.34f;
|
||||||
|
private static readonly Vector2 FootAnchor = new Vector2(640f, 604f); // ноги в кадре 1280x720
|
||||||
|
|
||||||
private Node2D _world;
|
private Node2D _world;
|
||||||
private Label _label;
|
private Label _label;
|
||||||
@@ -15,6 +19,18 @@ public partial class RoomMap : Node2D
|
|||||||
private float _viewZoom = 1f;
|
private float _viewZoom = 1f;
|
||||||
private Vector2 _homePos;
|
private Vector2 _homePos;
|
||||||
|
|
||||||
|
private readonly List<Pawn> _pawns = new();
|
||||||
|
private System.Random _rng;
|
||||||
|
|
||||||
|
private class Pawn
|
||||||
|
{
|
||||||
|
public Node2D Node;
|
||||||
|
public AnimationPlayer Ap;
|
||||||
|
public float X, TargetX, FloorY, Speed, MinX, MaxX, IdleTimer;
|
||||||
|
public bool Walking;
|
||||||
|
public string WalkAnim, IdleAnim;
|
||||||
|
}
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
var bg = new ColorRect
|
var bg = new ColorRect
|
||||||
@@ -65,6 +81,142 @@ public partial class RoomMap : Node2D
|
|||||||
for (int r = 0; r < Rows; r++)
|
for (int r = 0; r < Rows; r++)
|
||||||
for (int c = 0; c < Cols; c++)
|
for (int c = 0; c < Cols; c++)
|
||||||
AddCell("res://assets/room_sliced/Frame.png", c, r, 1, 1, new Color(1, 1, 1, 0.5f));
|
AddCell("res://assets/room_sliced/Frame.png", c, r, 1, 1, new Color(1, 1, 1, 0.5f));
|
||||||
|
|
||||||
|
BuildStairs();
|
||||||
|
BuildObjects();
|
||||||
|
BuildPawns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- лестницы (вертикальные шахты с перекладинами) ----------
|
||||||
|
private void BuildStairs()
|
||||||
|
{
|
||||||
|
AddLadder(2 * Cell);
|
||||||
|
AddLadder(4 * Cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddLadder(float centerX)
|
||||||
|
{
|
||||||
|
const float w = 48f;
|
||||||
|
float x = centerX - w / 2f;
|
||||||
|
float h = Rows * Cell;
|
||||||
|
AddRect(new Rect2(x, 0, w, h), new Color(0.10f, 0.08f, 0.06f, 0.9f)); // шахта
|
||||||
|
AddRect(new Rect2(x + 3, 0, 7, h), new Color(0.45f, 0.30f, 0.17f)); // рельс слева
|
||||||
|
AddRect(new Rect2(x + w - 10, 0, 7, h), new Color(0.45f, 0.30f, 0.17f)); // рельс справа
|
||||||
|
for (float ry = 22; ry < h; ry += 40)
|
||||||
|
AddRect(new Rect2(x + 6, ry, w - 12, 8), new Color(0.55f, 0.38f, 0.20f)); // ступени
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddRect(Rect2 r, Color c)
|
||||||
|
{
|
||||||
|
var p = new Polygon2D
|
||||||
|
{
|
||||||
|
Color = c,
|
||||||
|
Polygon = new[]
|
||||||
|
{
|
||||||
|
r.Position, new Vector2(r.End.X, r.Position.Y), r.End, new Vector2(r.Position.X, r.End.Y)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_world.AddChild(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- объекты в комнатах ----------
|
||||||
|
private void BuildObjects()
|
||||||
|
{
|
||||||
|
(int c, int r)[] lanterns = { (0, 0), (5, 0), (3, 1), (5, 2), (1, 3), (0, 4), (5, 4) };
|
||||||
|
foreach (var (c, r) in lanterns)
|
||||||
|
AddTex("res://assets/room_sliced/Lantern.png",
|
||||||
|
new Rect2(c * Cell + Cell * 0.72f, r * Cell + Cell * 0.06f, Cell * 0.16f, Cell * 0.22f), _world, Colors.White);
|
||||||
|
|
||||||
|
(int c, int r)[] lights = { (1, 1), (3, 3), (4, 0) };
|
||||||
|
foreach (var (c, r) in lights)
|
||||||
|
AddTex("res://assets/room_sliced/Light.png",
|
||||||
|
new Rect2(c * Cell + Cell * 0.28f, r * Cell + Cell * 0.02f, Cell * 0.44f, Cell * 0.44f), _world, new Color(1, 1, 1, 0.75f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- персонажи, гуляющие по этажам ----------
|
||||||
|
private void BuildPawns()
|
||||||
|
{
|
||||||
|
_rng = new System.Random(20260803);
|
||||||
|
(string path, int row)[] picks =
|
||||||
|
{
|
||||||
|
("res://characters/elf1/elf1_combat_native.tscn", 0),
|
||||||
|
("res://characters/knight/knight_combat_native.tscn", 1),
|
||||||
|
("res://characters/orc/orc_combat_native.tscn", 2),
|
||||||
|
("res://characters/sister/sister_combat_native.tscn", 3),
|
||||||
|
("res://characters/satyress/satyress_combat_native.tscn", 4),
|
||||||
|
};
|
||||||
|
float minX = Cell * 0.4f, maxX = Cols * Cell - Cell * 0.4f;
|
||||||
|
|
||||||
|
foreach (var (path, row) in picks)
|
||||||
|
{
|
||||||
|
if (!ResourceLoader.Exists(path)) continue;
|
||||||
|
var scene = ResourceLoader.Load<PackedScene>(path).Instantiate<Node2D>();
|
||||||
|
scene.Position = -FootAnchor * CharScale;
|
||||||
|
scene.Scale = new Vector2(CharScale, CharScale);
|
||||||
|
|
||||||
|
var node = new Node2D();
|
||||||
|
node.AddChild(scene);
|
||||||
|
_world.AddChild(node);
|
||||||
|
|
||||||
|
float floorY = row * Cell + Cell * 0.9f;
|
||||||
|
float x = (float)(_rng.NextDouble() * (maxX - minX) + minX);
|
||||||
|
node.Position = new Vector2(x, floorY);
|
||||||
|
|
||||||
|
var ap = scene.GetNodeOrNull<AnimationPlayer>("AnimationPlayer");
|
||||||
|
string[] anims = ap != null ? ap.GetAnimationList() : System.Array.Empty<string>();
|
||||||
|
var p = new Pawn
|
||||||
|
{
|
||||||
|
Node = node, Ap = ap, X = x, FloorY = floorY, MinX = minX, MaxX = maxX,
|
||||||
|
Speed = 70f + (float)_rng.NextDouble() * 55f,
|
||||||
|
WalkAnim = Pick(anims, "walk_0"), IdleAnim = Pick(anims, "idle_0"),
|
||||||
|
TargetX = (float)(_rng.NextDouble() * (maxX - minX) + minX)
|
||||||
|
};
|
||||||
|
StartWalk(p);
|
||||||
|
_pawns.Add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Pick(string[] anims, string want)
|
||||||
|
{
|
||||||
|
foreach (var a in anims) if (a == want) return a;
|
||||||
|
return anims.Length > 0 ? anims[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void StartWalk(Pawn p)
|
||||||
|
{
|
||||||
|
p.Walking = true;
|
||||||
|
if (p.Ap != null && p.WalkAnim != null) p.Ap.Play(p.WalkAnim);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartIdle(Pawn p)
|
||||||
|
{
|
||||||
|
p.Walking = false;
|
||||||
|
p.IdleTimer = 0.8f + (float)_rng.NextDouble() * 2.2f;
|
||||||
|
if (p.Ap != null && p.IdleAnim != null) p.Ap.Play(p.IdleAnim);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePawns(float dt)
|
||||||
|
{
|
||||||
|
foreach (var p in _pawns)
|
||||||
|
{
|
||||||
|
if (p.Walking)
|
||||||
|
{
|
||||||
|
float d = Mathf.Sign(p.TargetX - p.X);
|
||||||
|
p.X += d * p.Speed * dt;
|
||||||
|
p.Node.Scale = new Vector2(d >= 0 ? 1f : -1f, 1f);
|
||||||
|
p.Node.Position = new Vector2(p.X, p.FloorY);
|
||||||
|
if (Mathf.Abs(p.TargetX - p.X) < 4f) StartIdle(p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p.IdleTimer -= dt;
|
||||||
|
if (p.IdleTimer <= 0f)
|
||||||
|
{
|
||||||
|
p.TargetX = (float)(_rng.NextDouble() * (p.MaxX - p.MinX) + p.MinX);
|
||||||
|
StartWalk(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddCell(string path, int col, int row, int cw, int ch, Color? modulate = null)
|
private void AddCell(string path, int col, int row, int cw, int ch, Color? modulate = null)
|
||||||
@@ -114,7 +266,7 @@ public partial class RoomMap : Node2D
|
|||||||
private void UpdateLabel()
|
private void UpdateLabel()
|
||||||
{
|
{
|
||||||
_label.Text =
|
_label.Text =
|
||||||
$"Карта убежища — {Cols}×{Rows} комнат из игровых текстур\n" +
|
$"Карта убежища — {Cols}×{Rows} комнат, лестницы, объекты, {_pawns.Count} персонажа гуляют\n" +
|
||||||
$"ЛКМ/WASD — панорама · колесо — зум (x{_viewZoom:0.00}) · R — сброс · Esc — меню";
|
$"ЛКМ/WASD — панорама · колесо — зум (x{_viewZoom:0.00}) · R — сброс · Esc — меню";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +281,8 @@ public partial class RoomMap : Node2D
|
|||||||
if (Input.IsKeyPressed(Key.S) || Input.IsKeyPressed(Key.Down)) dir.Y -= 1;
|
if (Input.IsKeyPressed(Key.S) || Input.IsKeyPressed(Key.Down)) dir.Y -= 1;
|
||||||
if (dir != Vector2.Zero)
|
if (dir != Vector2.Zero)
|
||||||
_world.Position += dir * (float)delta * 600f;
|
_world.Position += dir * (float)delta * 600f;
|
||||||
|
|
||||||
|
UpdatePawns((float)delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _UnhandledInput(InputEvent @event)
|
public override void _UnhandledInput(InputEvent @event)
|
||||||
|
|||||||
Reference in New Issue
Block a user