From d6fc2026917d55fa12713e3d00004ec461cc5971 Mon Sep 17 00:00:00 2001 From: Matheus Date: Thu, 30 Oct 2025 17:31:00 -0300 Subject: vários andares MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/Map/DungeonGenerator.cs | 32 +++++++++++--------------- scripts/Map/FieldOfView.cs | 11 +++++++++ scripts/Map/Map.cs | 50 ++++++++++++++++++++++++++++++++++++++--- scripts/Map/MapData.cs | 10 +++++++++ scripts/Map/Tile.cs | 6 +++-- 5 files changed, 85 insertions(+), 24 deletions(-) (limited to 'scripts/Map') diff --git a/scripts/Map/DungeonGenerator.cs b/scripts/Map/DungeonGenerator.cs index 2d5ef8d..2b24e8a 100644 --- a/scripts/Map/DungeonGenerator.cs +++ b/scripts/Map/DungeonGenerator.cs @@ -2,6 +2,7 @@ using Godot; using TheLegendOfGustav.Entities.Actors; using TheLegendOfGustav.Entities; using TheLegendOfGustav.Entities.Items; +using System; namespace TheLegendOfGustav.Map; @@ -35,16 +36,6 @@ public partial class DungeonGenerator : Node [Export] private int height = 60; - /// - /// Qual seed utilizar. - /// - [Export] - private ulong seed; - /// - /// Se será utilizada a nossa seed ou a seed padrão da classe RandomNumberGenerator. - /// - [Export] - private bool useSeed = true; /// /// Quantas iterações do algoritmo chamar. /// @@ -73,14 +64,6 @@ public partial class DungeonGenerator : Node #endregion #region Methods - public override void _Ready() - { - base._Ready(); - if (useSeed) - { - rng.Seed = seed; - } - } /// /// Gera um andar da masmorra. @@ -89,9 +72,12 @@ public partial class DungeonGenerator : Node /// /// Jogador. /// O mapa gerado. - public MapData GenerateDungeon(Player player) + public MapData GenerateDungeon(Player player, int currentFloor) { + rng.Seed = (ulong)DateTimeOffset.Now.ToUnixTimeMilliseconds(); + MapData data = new MapData(width, height, player); + data.CurrentFloor = currentFloor; // Divisão mestre que engloba o mapa inteiro. MapDivision root = new MapDivision(0, 0, width, height); @@ -104,6 +90,8 @@ public partial class DungeonGenerator : Node // Coloca os corredores. TunnelDivisions(data, root); + Rect2I lastRoom = new(0, 0, 0, 0); + // Cria as salas com base nas divisões geradas. foreach (MapDivision division in root.GetLeaves()) { @@ -127,8 +115,14 @@ public partial class DungeonGenerator : Node } // Colocamos os inimigos na sala. PlaceEntities(data, room); + + lastRoom = room; } + data.DownstairsLocation = lastRoom!.GetCenter(); + Tile downTile = data.GetTile(data.DownstairsLocation); + downTile.Key = TileType.DOWN_STAIRS; + // Feito o mapa, inicializamos o algoritmo de pathfinding. data.SetupPathfinding(); return data; diff --git a/scripts/Map/FieldOfView.cs b/scripts/Map/FieldOfView.cs index 40df320..474c1ca 100644 --- a/scripts/Map/FieldOfView.cs +++ b/scripts/Map/FieldOfView.cs @@ -101,6 +101,17 @@ public partial class FieldOfView : Node fov.Clear(); } + /// + /// Diferença de ClearFOV: não referencia tiles. + /// No contexto onde ResetFOV é chamado, os tiles não + /// podem ser referenciados porque já foram liberados da + /// memória. + /// + public void ResetFOV() + { + fov.Clear(); + } + public void UpdateFOV(MapData data, Vector2I position, int radius) { ClearFOV(); diff --git a/scripts/Map/Map.cs b/scripts/Map/Map.cs index 04ccabd..2913c1f 100644 --- a/scripts/Map/Map.cs +++ b/scripts/Map/Map.cs @@ -2,6 +2,7 @@ using System.Net.Http.Headers; using Godot; using TheLegendOfGustav.Entities; using TheLegendOfGustav.Entities.Actors; +using TheLegendOfGustav.Utils; namespace TheLegendOfGustav.Map; @@ -30,7 +31,11 @@ public partial class Map : Node2D /// Dados do mapa. /// public MapData MapData { get; private set; } - + + [Signal] + public delegate void DungeonFloorChangedEventHandler(int floor); + + private SignalBus.PlayerDescentEventHandler joinSignal; public override void _Ready() { base._Ready(); @@ -39,20 +44,46 @@ public partial class Map : Node2D fieldOfView = GetNode("FieldOfView"); tilesNode = GetNode("Tiles"); entitiesNode = GetNode("Entities"); + + joinSignal = () => NextFloor(); + SignalBus.Instance.PlayerDescent += joinSignal; + } + + void NextFloor() + { + Player player = MapData.Player; + entitiesNode.RemoveChild(player); + + foreach (var entity in entitiesNode.GetChildren()) + { + entity.QueueFree(); + } + + foreach (var tile in tilesNode.GetChildren()) + { + tile.QueueFree(); + } + + Generate(player, MapData.CurrentFloor + 1); + player.GetNode("Camera2D").MakeCurrent(); + fieldOfView.ResetFOV(); + UpdateFOV(player.GridPosition); } /// /// Cria um andar da masmorra utilizando o gerador de mapa. /// /// O gerador de mapas precisa do jogador. - public void Generate(Player player) + public void Generate(Player player, int currentFloor = 1) { - MapData = generator.GenerateDungeon(player); + MapData = generator.GenerateDungeon(player, currentFloor); MapData.EntityPlaced += OnEntityPlaced; PlaceTiles(); PlaceEntities(); + + EmitSignal(SignalName.DungeonFloorChanged, currentFloor); } /// @@ -111,6 +142,19 @@ public partial class Map : Node2D PlaceEntities(); MapData.EntityPlaced += OnEntityPlaced; + EmitSignal(SignalName.DungeonFloorChanged, MapData.CurrentFloor); return true; } + + public override void _Notification(int what) + { + if (what == NotificationPredelete) + { + if (joinSignal != null) + { + SignalBus.Instance.PlayerDescent -= joinSignal; + } + } + base._Notification(what); + } } diff --git a/scripts/Map/MapData.cs b/scripts/Map/MapData.cs index 5f96743..907e8d0 100644 --- a/scripts/Map/MapData.cs +++ b/scripts/Map/MapData.cs @@ -84,6 +84,10 @@ public partial class MapData : RefCounted, ISaveable return list; } } + + public int CurrentFloor { get; set; } = 0; + + public Vector2I DownstairsLocation { get; set; } /// /// Objeto do Godot que utiliza do algoritmo A* para calcular /// caminhos e rotas. @@ -349,6 +353,9 @@ public partial class MapData : RefCounted, ISaveable {"player", Player.GetSaveData()}, {"width", Width}, {"height", Height}, + {"current_floor", CurrentFloor}, + {"down_stairs_location_x", DownstairsLocation.X}, + {"down_stairs_location_y", DownstairsLocation.Y} }; } @@ -357,6 +364,9 @@ public partial class MapData : RefCounted, ISaveable Width = (int)saveData["width"]; Height = (int)saveData["height"]; + CurrentFloor = (int)saveData["current_floor"]; + DownstairsLocation = new((int)saveData["down_stairs_location_x"], (int)saveData["down_stairs_location_y"]); + SetupTiles(); Array> serializedTiles = (Array>)saveData["tiles"]; diff --git a/scripts/Map/Tile.cs b/scripts/Map/Tile.cs index 6790f3e..03039e0 100644 --- a/scripts/Map/Tile.cs +++ b/scripts/Map/Tile.cs @@ -8,7 +8,8 @@ namespace TheLegendOfGustav.Map; public enum TileType { WALL, - FLOOR + FLOOR, + DOWN_STAIRS } /// @@ -22,7 +23,8 @@ public partial class Tile : Sprite2D, ISaveable private static readonly Godot.Collections.Dictionary Types = new() { {TileType.WALL, GD.Load("res://assets/definitions/tiles/wall.tres")}, - {TileType.FLOOR, GD.Load("res://assets/definitions/tiles/floor.tres")} + {TileType.FLOOR, GD.Load("res://assets/definitions/tiles/floor.tres")}, + {TileType.DOWN_STAIRS, GD.Load("res://assets/definitions/tiles/downstairs.tres")} }; TileType key; -- cgit v1.2.3