From 832fe5e98842123bcc9d0c3245babf172bb10578 Mon Sep 17 00:00:00 2001 From: Matheus Date: Mon, 25 Aug 2025 13:42:29 -0300 Subject: Gerador melhorado. --- scenes/Game.tscn | 5 ++- scripts/map/DungeonGenerator.cs | 72 ++++++++++++++++++++--------------------- scripts/map/MapDivision.cs | 71 ++++++++++++++++++++++++++++++++++++++++ scripts/map/MapDivision.cs.uid | 1 + 4 files changed, 109 insertions(+), 40 deletions(-) create mode 100644 scripts/map/MapDivision.cs create mode 100644 scripts/map/MapDivision.cs.uid diff --git a/scenes/Game.tscn b/scenes/Game.tscn index 484d67a..8948ee9 100644 --- a/scenes/Game.tscn +++ b/scenes/Game.tscn @@ -17,9 +17,8 @@ script = ExtResource("3_cpr0p") [node name="Generator" type="Node" parent="Map"] script = ExtResource("4_78awf") seed = 989 -maxRooms = 30 -roomMinWidth = 4 -roomMinHeight = 5 +useSeed = false +iterations = 8 [node name="Actors" type="Node2D" parent="."] diff --git a/scripts/map/DungeonGenerator.cs b/scripts/map/DungeonGenerator.cs index 75b375d..0d94724 100644 --- a/scripts/map/DungeonGenerator.cs +++ b/scripts/map/DungeonGenerator.cs @@ -1,5 +1,6 @@ using Godot; using System; +using System.Drawing; using System.Linq; using System.Net.NetworkInformation; @@ -18,15 +19,7 @@ public partial class DungeonGenerator : Node [Export] private bool useSeed = true; [Export] - private int maxRooms = 10; - [Export] - private int roomMaxWidth = 10; - [Export] - private int roomMinWidth = 3; - [Export] - private int roomMaxHeight = 10; - [Export] - private int roomMinHeight = 2; + private int iterations = 3; public override void _Ready() { @@ -46,11 +39,9 @@ public partial class DungeonGenerator : Node private static void CarveRoom(MapData data, Rect2I room) { - Rect2I inner = room.Grow(-1); - - for (int y = inner.Position.Y; y <= inner.End.Y; y++) + for (int y = room.Position.Y; y < room.End.Y; y++) { - for (int x = inner.Position.X; x <= inner.End.X; x++) + for (int x = room.Position.X; x < room.End.X; x++) { CarveTile(data, new Vector2I(x, y)); } @@ -61,35 +52,32 @@ public partial class DungeonGenerator : Node { MapData data = new MapData(width, height); - Godot.Collections.Array rooms = []; - - for (int tryroom = 0; tryroom < maxRooms; tryroom++) { - int roomWidth = rng.RandiRange(roomMinWidth, roomMaxWidth); - int roomHeight = rng.RandiRange(roomMinHeight, roomMaxHeight); + MapDivision root = new MapDivision(0, 0, width, height); - int x = rng.RandiRange(0, data.Width - 1 - roomWidth); - int y = rng.RandiRange(0, data.Height - 1 - roomHeight); + root.Split(iterations, rng); - Rect2I newRoom = new(x, y, roomWidth, roomHeight); + bool first = true; - bool intersects = false; - foreach (Rect2I room in rooms) { - if (newRoom.Intersects(room)) { - intersects = true; - break; - } - } - if (intersects) { - continue; - } + TunnelDivisions(data, root); - CarveRoom(data, newRoom); - if (rooms.Count <= 0) { - player.GridPosition = newRoom.GetCenter(); - } else { - TunnelBetween(data, rooms.Last().GetCenter(), newRoom.GetCenter()); + foreach(MapDivision division in root.GetLeaves()) + { + Rect2I room = new(division.Position, division.Size); + + room = room.GrowIndividual( + -rng.RandiRange(1, 2), + -rng.RandiRange(1, 2), + -rng.RandiRange(1, 2), + -rng.RandiRange(1, 2) + ); + + GD.Print($"Division {room}"); + CarveRoom(data, room); + if (first) + { + first = false; + player.GridPosition = room.GetCenter(); } - rooms.Add(newRoom); } return data; @@ -115,4 +103,14 @@ public partial class DungeonGenerator : Node HorizontalCorridor(data, start.Y, start.X, end.X); VerticalCorridor(data, end.X, start.Y, end.Y); } + + private void TunnelDivisions(MapData data, MapDivision root) { + if (root.IsLeaf) { + return; + } + + TunnelBetween(data, root.Right.Center, root.Left.Center); + TunnelDivisions(data, root.Left); + TunnelDivisions(data, root.Right); + } } diff --git a/scripts/map/MapDivision.cs b/scripts/map/MapDivision.cs new file mode 100644 index 0000000..15a6be8 --- /dev/null +++ b/scripts/map/MapDivision.cs @@ -0,0 +1,71 @@ +using System.Linq; +using System.Numerics; +using System.Xml.Schema; +using Godot; + +public partial class MapDivision : RefCounted { + public Vector2I Position { get; set; } + public Vector2I Size { get; set; } + + public Vector2I Center { + get => new(Position.X + Size.X/2, Position.Y + Size.Y/2); + } + + private MapDivision left; + public MapDivision Left { get => this.left; } + private MapDivision right; + public MapDivision Right { get => this.right; } + + public bool IsLeaf { + get => left == null && right == null; + } + + public MapDivision(Vector2I position, Vector2I size) { + Position = position; + Size = size; + } + + public MapDivision(Vector2I position, int width, int height) { + Position = position; + Size = new(width, height); + } + + public MapDivision(int x, int y, int width, int height) { + Position = new(x, y); + Size = new(width, height); + } + + public Godot.Collections.Array GetLeaves() { + if (IsLeaf) { + Godot.Collections.Array list = []; + list.Add(this); + return list; + } + return left.GetLeaves() + right.GetLeaves(); + } + + public void Split(int iterations, RandomNumberGenerator rng) { + float SplitRatio = rng.RandfRange(0.35f, 0.65f); + bool horizontalSplit = Size.X <= Size.Y; + + if (horizontalSplit) { + int leftHeight = (int) (Size.Y * SplitRatio); + if (leftHeight > 4 && Size.Y - leftHeight > 4) { + left = new MapDivision(Position, Size.X, leftHeight); + right = new MapDivision(Position.X, Position.Y + leftHeight, Size.X, Size.Y - leftHeight); + } + } else { + int leftWidth = (int) (Size.Y * SplitRatio); + + if (leftWidth > 4 && Size.Y - leftWidth > 4) { + left = new MapDivision(Position, leftWidth, Size.Y); + right = new MapDivision(Position.X + leftWidth, Position.Y, Size.X - leftWidth, Size.Y); + } + } + + if (iterations > 1) { + left?.Split(iterations - 1, rng); + right?.Split(iterations - 1, rng); + } + } +} \ No newline at end of file diff --git a/scripts/map/MapDivision.cs.uid b/scripts/map/MapDivision.cs.uid new file mode 100644 index 0000000..fdd53a4 --- /dev/null +++ b/scripts/map/MapDivision.cs.uid @@ -0,0 +1 @@ +uid://c3niegr686acj -- cgit v1.2.3