diff options
| author | Matheus <matheus.guedes.mg.m@gmail.com> | 2025-10-26 20:02:15 -0300 |
|---|---|---|
| committer | Matheus <matheus.guedes.mg.m@gmail.com> | 2025-10-26 20:02:15 -0300 |
| commit | f4ed469fc9eaeebf39093fbf6601581cc10c6e2f (patch) | |
| tree | d8f29ae3288e950b5fb1f5251845d57949ca2ac0 /scripts/Map | |
| parent | 639cd8cef403e9e66bf31e7888e786effac2b292 (diff) | |
feat:save AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
O vazio dentro de mim é como uma xícara de café esquecida
no canto da mesa.
Diffstat (limited to 'scripts/Map')
| -rw-r--r-- | scripts/Map/DungeonGenerator.cs | 2 | ||||
| -rw-r--r-- | scripts/Map/Map.cs | 18 | ||||
| -rw-r--r-- | scripts/Map/MapData.cs | 120 | ||||
| -rw-r--r-- | scripts/Map/Tile.cs | 49 |
4 files changed, 181 insertions, 8 deletions
diff --git a/scripts/Map/DungeonGenerator.cs b/scripts/Map/DungeonGenerator.cs index 7e447b0..2d5ef8d 100644 --- a/scripts/Map/DungeonGenerator.cs +++ b/scripts/Map/DungeonGenerator.cs @@ -144,7 +144,7 @@ public partial class DungeonGenerator : Node Tile tile = data.GetTile(pos); if (tile == null) return; - tile.SetDefinition(MapData.floorDefinition); + tile.Key = TileType.FLOOR; } /// <summary> diff --git a/scripts/Map/Map.cs b/scripts/Map/Map.cs index 8521797..04ccabd 100644 --- a/scripts/Map/Map.cs +++ b/scripts/Map/Map.cs @@ -1,3 +1,4 @@ +using System.Net.Http.Headers; using Godot; using TheLegendOfGustav.Entities; using TheLegendOfGustav.Entities.Actors; @@ -95,4 +96,21 @@ public partial class Map : Node2D { entitiesNode.AddChild(entity); } + + public bool LoadGame(Player player) + { + + MapData = new(0, 0, player); + + if (!MapData.LoadGame()) + { + return false; + } + + PlaceTiles(); + PlaceEntities(); + + MapData.EntityPlaced += OnEntityPlaced; + return true; + } } diff --git a/scripts/Map/MapData.cs b/scripts/Map/MapData.cs index 49e4ca0..5f96743 100644 --- a/scripts/Map/MapData.cs +++ b/scripts/Map/MapData.cs @@ -1,4 +1,5 @@ using Godot; +using Godot.Collections; using TheLegendOfGustav.Entities; using TheLegendOfGustav.Entities.Actors; using TheLegendOfGustav.Entities.Items; @@ -10,11 +11,9 @@ namespace TheLegendOfGustav.Map; /// O mapa é o cenário onde as ações do jogo ocorrem. /// Mais especificamente, o mapa é um único andar da masmorra. /// </summary> -public partial class MapData : RefCounted +public partial class MapData : RefCounted, ISaveable { #region Fields - public static readonly TileDefinition wallDefinition = GD.Load<TileDefinition>("res://assets/definitions/tiles/wall.tres"); - public static readonly TileDefinition floorDefinition = GD.Load<TileDefinition>("res://assets/definitions/tiles/floor.tres"); /// <summary> /// Peso do ator no pathfinder. /// A IA irá evitar de passar por espaços com peso alto. @@ -275,11 +274,16 @@ public partial class MapData : RefCounted /// </summary> private void SetupTiles() { + if (Tiles.Count > 1) + { + Tiles.Clear(); + } + for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { - Tiles.Add(new Tile(new Vector2I(j, i), wallDefinition)); + Tiles.Add(new Tile(new Vector2I(j, i), TileType.WALL)); } } } @@ -314,5 +318,113 @@ public partial class MapData : RefCounted return true; } + + public Dictionary<string, Variant> GetSaveData() + { + Array<Dictionary<string, Variant>> serializedTiles = []; + Array<Dictionary<string, Variant>> serializedItemEntities = []; + Array<Dictionary<string, Variant>> serializedEnemies = []; + foreach (Tile tile in Tiles) + { + serializedTiles.Add(tile.GetSaveData()); + } + + foreach (Entity ent in Entities) + { + if (ent is Enemy enemy) + { + serializedEnemies.Add(enemy.GetSaveData()); + } + else if (ent is ItemEntity it) + { + serializedItemEntities.Add(it.GetSaveData()); + } + } + + return new() + { + {"tiles", serializedTiles}, + {"enemies", serializedEnemies}, + {"items", serializedItemEntities}, + {"player", Player.GetSaveData()}, + {"width", Width}, + {"height", Height}, + }; + } + + public bool LoadSaveData(Dictionary<string, Variant> saveData) + { + Width = (int)saveData["width"]; + Height = (int)saveData["height"]; + + SetupTiles(); + + Array<Dictionary<string, Variant>> serializedTiles = (Array<Dictionary<string, Variant>>)saveData["tiles"]; + Array<Dictionary<string, Variant>> serializedItemEntities = (Array<Dictionary<string, Variant>>)saveData["items"]; + Array<Dictionary<string, Variant>> serializedEnemies = (Array<Dictionary<string, Variant>>)saveData["enemies"]; + + for (int i = 0; i < serializedTiles.Count; i++) + { + if (!Tiles[i].LoadSaveData(serializedTiles[i])) + { + return false; + } + } + SetupPathfinding(); + if (!Player.LoadSaveData((Dictionary<string, Variant>)saveData["player"])) + { + return false; + } + + Player.MapData = this; + + foreach(Dictionary<string, Variant> enemy in serializedEnemies) + { + Enemy en = new(Vector2I.Zero, this); + if (!en.LoadSaveData(enemy)) + { + return false; + } + + InsertEntity(en); + } + + foreach(Dictionary<string, Variant> item in serializedItemEntities) + { + ItemEntity en = new(Vector2I.Zero, this); + + if (!en.LoadSaveData(item)) + { + return false; + } + + InsertEntity(en); + } + + return true; + } + + public void SaveGame() + { + using var saveFile = FileAccess.Open("user://save_game.json", FileAccess.ModeFlags.Write); + var saveData = GetSaveData(); + string saveString = Json.Stringify(saveData); + + saveFile.StoreLine(saveString); + } + + public bool LoadGame() + { + using var saveFile = FileAccess.Open("user://save_game.json", FileAccess.ModeFlags.Read); + string saveString = saveFile.GetLine(); + var saveData = (Dictionary<string, Variant>)Json.ParseString(saveString); + + if (!LoadSaveData(saveData)) + { + return false; + } + + return true; + } #endregion } diff --git a/scripts/Map/Tile.cs b/scripts/Map/Tile.cs index 488d124..6790f3e 100644 --- a/scripts/Map/Tile.cs +++ b/scripts/Map/Tile.cs @@ -1,16 +1,41 @@ +using System.Threading; using Godot; +using Godot.Collections; using TheLegendOfGustav.Utils; namespace TheLegendOfGustav.Map; +public enum TileType +{ + WALL, + FLOOR +} + /// <summary> /// O mundo do jogo é composto por Tiles. /// Um tile é um quadrado de 16x16 que representa uma /// unidade discreta do cenário. Tiles podem agir como /// parede, chão, ou outras funções. /// </summary> -public partial class Tile : Sprite2D +public partial class Tile : Sprite2D, ISaveable { + private static readonly Godot.Collections.Dictionary<TileType, TileDefinition> Types = new() + { + {TileType.WALL, GD.Load<TileDefinition>("res://assets/definitions/tiles/wall.tres")}, + {TileType.FLOOR, GD.Load<TileDefinition>("res://assets/definitions/tiles/floor.tres")} + }; + + TileType key; + public TileType Key + { + get => key; + set + { + key = value; + SetDefinition(Types[value]); + } + } + private bool isExplored = false; private bool isInView = false; @@ -19,7 +44,7 @@ public partial class Tile : Sprite2D /// </summary> private TileDefinition definition; - public Tile(Vector2I pos, TileDefinition definition) + public Tile(Vector2I pos, TileType type) { // Tile herda da classe Sprite2D. // Por padrão, a posição do Sprite2D é no centro de sua textura. @@ -29,7 +54,7 @@ public partial class Tile : Sprite2D // Tiles começam invisíveis porque não foram vistos pelo jogador. Visible = false; Position = Grid.GridToWorld(pos); - SetDefinition(definition); + Key = type; } /// <summary> @@ -89,4 +114,22 @@ public partial class Tile : Sprite2D IsWalkable = definition.IsWalkable; IsTransparent = definition.IsTransparent; } + + public Dictionary<string, Variant> GetSaveData() + { + return new() + { + {"key", (int)Key}, + {"is_explored", IsExplored} + }; + } + + public bool LoadSaveData(Dictionary<string, Variant> saveData) + { + // É o seguinte, não tenho tempo, não vou verificar se a entrada está correta. + Key = (TileType)(int)saveData["key"]; + + IsExplored = (bool)saveData["is_explored"]; + return true; + } } |
