diff --git a/Scenes/Root.tscn b/Scenes/Root.tscn index dc4d054..05c400b 100644 --- a/Scenes/Root.tscn +++ b/Scenes/Root.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=5 format=3 uid="uid://c22aprj452aha"] +[gd_scene load_steps=6 format=3 uid="uid://c22aprj452aha"] [ext_resource type="Script" uid="uid://cudpc3w17mbsw" path="res://Scripts/System/GridManager.cs" id="1_knkkn"] [ext_resource type="Script" uid="uid://cfbj72nm0eovg" path="res://Scripts/System/BuildingRegistry.cs" id="1_sxhdm"] +[ext_resource type="Script" uid="uid://cugfbvw70clgd" path="res://Scripts/System/NaturalResourceGenerator.cs" id="2_oss8w"] [ext_resource type="Script" uid="uid://bx1wj7gn6vrqe" path="res://Scripts/System/PlacementManager.cs" id="2_sxhdm"] [ext_resource type="PackedScene" uid="uid://doxy60afddg1m" path="res://Scenes/Entities/Player.tscn" id="3_oss8w"] @@ -10,6 +11,11 @@ [node name="BuildingRegistry" type="Node" parent="."] script = ExtResource("1_sxhdm") +[node name="NaturalResourceGenerator" type="Node2D" parent="." node_paths=PackedStringArray("Grid", "Registry")] +script = ExtResource("2_oss8w") +Grid = NodePath("../GridSystem") +Registry = NodePath("../BuildingRegistry") + [node name="GridSystem" type="Node2D" parent="."] script = ExtResource("1_knkkn") diff --git a/Scenes/Tiles/GroundTile.tscn b/Scenes/Tiles/GroundTile.tscn index bc82be9..ce20bf9 100644 --- a/Scenes/Tiles/GroundTile.tscn +++ b/Scenes/Tiles/GroundTile.tscn @@ -7,6 +7,7 @@ size = Vector2(54, 54) [node name="GroundTile" type="StaticBody2D"] +collision_layer = 0 script = ExtResource("1_mqsaf") [node name="Sprite2D" type="Sprite2D" parent="."] diff --git a/Scenes/Tiles/StoneIronTile.tscn b/Scenes/Tiles/StoneIronTile.tscn index 6098b1d..817308b 100644 --- a/Scenes/Tiles/StoneIronTile.tscn +++ b/Scenes/Tiles/StoneIronTile.tscn @@ -7,6 +7,7 @@ size = Vector2(54, 54) [node name="StoneIronTile" type="StaticBody2D"] +collision_layer = 0 script = ExtResource("1_ewklp") [node name="Sprite2D" type="Sprite2D" parent="."] diff --git a/Scenes/Tiles/StoneTile.tscn b/Scenes/Tiles/StoneTile.tscn index 4408605..ec84287 100644 --- a/Scenes/Tiles/StoneTile.tscn +++ b/Scenes/Tiles/StoneTile.tscn @@ -7,6 +7,7 @@ size = Vector2(54, 54) [node name="StoneTile" type="StaticBody2D"] +collision_layer = 0 script = ExtResource("1_rndy8") [node name="Sprite2D" type="Sprite2D" parent="."] diff --git a/Scripts/System/GridManager.cs b/Scripts/System/GridManager.cs index 3772765..2d49ad1 100644 --- a/Scripts/System/GridManager.cs +++ b/Scripts/System/GridManager.cs @@ -1,6 +1,7 @@ #nullable enable using System; using System.Collections.Generic; +using System.Linq; using Godot; namespace AceFieldNewHorizon.Scripts.System; @@ -21,21 +22,13 @@ public partial class GridManager : Node { // Initialize all layers foreach (GridLayer layer in Enum.GetValues(typeof(GridLayer))) - { _layers[layer] = new Dictionary(); - } } public bool IsAreaFree(Vector2I topLeft, Vector2I size, float rotation, GridLayer layer = GridLayer.Building) { var occupiedCells = GridUtils.GetOccupiedCells(topLeft, size, rotation); - foreach (var cell in occupiedCells) - { - if (_layers[layer].ContainsKey(cell)) - return false; - } - - return true; + return occupiedCells.All(cell => !_layers[layer].ContainsKey(cell)); } public void OccupyArea(Vector2I topLeft, Node2D building, Vector2I size, float rotation, diff --git a/Scripts/System/NaturalResourceGenerator.cs b/Scripts/System/NaturalResourceGenerator.cs new file mode 100644 index 0000000..d7acd03 --- /dev/null +++ b/Scripts/System/NaturalResourceGenerator.cs @@ -0,0 +1,153 @@ +using Godot; +using System.Collections.Generic; +using AceFieldNewHorizon.Scripts.Tiles; + +namespace AceFieldNewHorizon.Scripts.System; + +public partial class NaturalResourceGenerator : Node2D +{ + [Export] public GridManager Grid { get; set; } + [Export] public BuildingRegistry Registry { get; set; } + + [Export] public int MapWidth = 100; + [Export] public int MapHeight = 100; + [Export] public float StoneDensity = 0.1f; // 10% chance for stone + [Export] public float IronDensity = 0.03f; // 3% chance for iron (within stone) + [Export] public int MinStoneVeinSize = 1; + [Export] public int MaxStoneVeinSize = 5; + [Export] public int MinIronVeinSize = 1; + [Export] public int MaxIronVeinSize = 3; + [Export] public int Seed; + + private RandomNumberGenerator _rng; + private readonly List _groundTiles = []; + private readonly List _stoneTiles = []; + private readonly List _ironTiles = []; + + public override void _Ready() + { + _rng = new RandomNumberGenerator(); + _rng.Seed = (ulong)(Seed != 0 ? Seed : (int)GD.Randi()); + + GenerateTerrain(); + PlaceResources(); + } + + private void GenerateTerrain() + { + // First pass: Generate base ground tiles + for (int x = 0; x < MapWidth; x++) + { + for (int y = 0; y < MapHeight; y++) + { + var cell = new Vector2I(x, y); + _groundTiles.Add(cell); + PlaceTile("ground", cell); + } + } + } + + private void PlaceResources() + { + // Create a copy of ground tiles for iteration + var groundTilesToProcess = new List(_groundTiles); + + // Place stone veins + foreach (var cell in groundTilesToProcess) + { + if (_rng.Randf() < StoneDensity) + { + var veinSize = _rng.RandiRange(MinStoneVeinSize, MaxStoneVeinSize); + PlaceVein(cell, "stone", veinSize, _stoneTiles); + } + } + + // Create a copy of stone tiles for iteration + var stoneTilesToProcess = new List(_stoneTiles); + + // Place iron veins within stone + foreach (var stoneCell in stoneTilesToProcess) + { + if (_rng.Randf() < IronDensity) + { + var veinSize = _rng.RandiRange(MinIronVeinSize, MaxIronVeinSize); + PlaceVein(stoneCell, "stone_iron", veinSize, _ironTiles); + } + } + } + + private void PlaceVein(Vector2I startCell, string tileType, int maxVeinSize, ICollection tileList) + { + var queue = new Queue(); + var placed = new HashSet(); + queue.Enqueue(startCell); + + int placedCount = 0; + + while (queue.Count > 0 && placedCount < maxVeinSize) + { + var cell = queue.Dequeue(); + if (placed.Contains(cell)) continue; + if (!IsInBounds(cell)) continue; + + switch (tileType) + { + // For iron, make sure we're placing on stone + case "stone_iron" when !_stoneTiles.Contains(cell): + continue; + // Remove from previous layer if needed + case "stone_iron" when _stoneTiles.Contains(cell): + _stoneTiles.Remove(cell); + break; + case "stone" when _groundTiles.Contains(cell): + _groundTiles.Remove(cell); + break; + } + + PlaceTile(tileType, cell); + tileList.Add(cell); + placed.Add(cell); + placedCount++; + + // Add adjacent cells to queue + for (var dx = -1; dx <= 1; dx++) + { + for (var dy = -1; dy <= 1; dy++) + { + if (dx == 0 && dy == 0) continue; // Skip self + var neighbor = new Vector2I(cell.X + dx, cell.Y + dy); + if (!placed.Contains(neighbor) && IsInBounds(neighbor)) + { + queue.Enqueue(neighbor); + } + } + } + } + } + + private bool IsInBounds(Vector2I cell) + { + return cell.X >= 0 && cell.X < MapWidth && + cell.Y >= 0 && cell.Y < MapHeight; + } + + private void PlaceTile(string tileType, Vector2I cell) + { + var building = Registry.GetBuilding(tileType); + if (building == null) return; + + var scene = building.Scene; + var instance = (BaseTile)scene.Instantiate(); + + // Match PlacementManager's positioning logic + var rotatedSize = building.GetRotatedSize(0f); + var offset = GridUtils.GetCenterOffset(rotatedSize, 0f); + instance.Position = GridUtils.GridToWorld(cell) + offset; + + instance.ZIndex = (int)building.Layer; + AddChild(instance); + + // Make sure to use the building's size from the registry + Grid.OccupyArea(cell, instance, building.Size, 0f, building.Layer); + } +} diff --git a/Scripts/System/NaturalResourceGenerator.cs.uid b/Scripts/System/NaturalResourceGenerator.cs.uid new file mode 100644 index 0000000..7153470 --- /dev/null +++ b/Scripts/System/NaturalResourceGenerator.cs.uid @@ -0,0 +1 @@ +uid://cugfbvw70clgd diff --git a/Scripts/System/PlacementManager.cs b/Scripts/System/PlacementManager.cs index 80572a4..980ecf5 100644 --- a/Scripts/System/PlacementManager.cs +++ b/Scripts/System/PlacementManager.cs @@ -165,8 +165,8 @@ public partial class PlacementManager : Node2D return layer switch { GridLayer.Ground => [GridLayer.Ground], - GridLayer.Building => [GridLayer.Ground, GridLayer.Building], - GridLayer.Decoration => [GridLayer.Ground, GridLayer.Building, GridLayer.Decoration], + GridLayer.Building => [GridLayer.Building], + GridLayer.Decoration => [GridLayer.Decoration], _ => [] }; }