✨ Natural resource generator
This commit is contained in:
		| @@ -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<Vector2I, (Node2D, Vector2I, float)>(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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, | ||||
|   | ||||
							
								
								
									
										153
									
								
								Scripts/System/NaturalResourceGenerator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								Scripts/System/NaturalResourceGenerator.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -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<Vector2I> _groundTiles = []; | ||||
| 	private readonly List<Vector2I> _stoneTiles = []; | ||||
| 	private readonly List<Vector2I> _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<Vector2I>(_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<Vector2I>(_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<Vector2I> tileList) | ||||
| 	{ | ||||
| 		var queue = new Queue<Vector2I>(); | ||||
| 		var placed = new HashSet<Vector2I>(); | ||||
| 		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); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										1
									
								
								Scripts/System/NaturalResourceGenerator.cs.uid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Scripts/System/NaturalResourceGenerator.cs.uid
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| uid://cugfbvw70clgd | ||||
| @@ -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], | ||||
|             _ => [] | ||||
|         }; | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user