using Godot; using System; using System.Collections.Generic; using System.Linq; using static GameData; public partial class World : Node3D { public Dictionary tileMeshes; public Dictionary contentMeshes; public Dictionary> tilePlaceholders; PackedScene layerPrefab = ResourceLoader.LoadLayerPrefab(); private Dictionary multiMeshes = new(); private Dictionary meshLibrary = new(); Layer layerNode; Pathfinding pathfinding; private MultiMeshHandler multiMeshHandler; public override void _Ready() { WFC.FillAdjacencies(); tileMeshes = ResourceLoader.LoadTiles(); contentMeshes = ResourceLoader.LoadDecorations(); tilePlaceholders = new Dictionary>(); foreach (var kvp in tileMeshes) { tilePlaceholders[kvp.Key] = new List(); foreach (Node3D child in kvp.Value.GetChildren()) { tilePlaceholders[kvp.Key].Add(new Placeholder(child.Name, child.Transform)); } meshLibrary[kvp.Key] = kvp.Value.Mesh; kvp.Value.QueueFree(); } multiMeshes = CreateMultiMeshes(meshLibrary); multiMeshHandler = new MultiMeshHandler(multiMeshes); map = new Layer[ruinSize]; GenerateWorld(); Pathfinding.BuildAStarGraph(); HandleRenderData(BuildRenderData(0)); } private Dictionary CreateMultiMeshes(Dictionary meshLibrary) { var result = new Dictionary(); foreach (var kvp in meshLibrary) { var mm = new MultiMesh { Mesh = kvp.Value, TransformFormat = MultiMesh.TransformFormatEnum.Transform3D }; var instance = new MultiMeshInstance3D { Multimesh = mm }; AddChild(instance); result[kvp.Key] = instance; } return result; } // Called every frame. 'delta' is the elapsed time since the previous frame. public override void _Process(double delta) { if (!canMove) return; if (Input.IsActionJustPressed("layer_up") && currentLayer > 0) currentLayer--; if (Input.IsActionJustPressed("layer_down") && currentLayer < ruinSize - 1) currentLayer++; if (currentLayer != visibleLayer) { map[visibleLayer].ClearDecorations(); HandleRenderData(BuildRenderData(currentLayer)); visibleLayer = currentLayer; } if (Input.IsActionJustPressed("spawn_robot") && robots.Count < maxRobotCount) { Robot robot = ResourceLoader.LoadRobotPrefab().Instantiate(); robot.Name = $"Robot #{robots.Count + 1}"; robot.Position = map[0].tiles[0,0].Position; AddChild(robot); robots.Add(robot); } } private void GenerateWorld() { for (int layer = 0; layer < ruinSize; layer++) { layerNode = layerPrefab.Instantiate(); AddChild(layerNode); if (layer == 0) { layerNode.SetupLayer(layerSize, layer, tileMeshes, new Vector2I()); } else { layerNode.SetupLayer(layerSize, layer, tileMeshes, map[layer - 1].gateCoordinate); } map[layer] = layerNode; } map[0].tiles[0,0].wasVisited = true; map[0].tiles[0,0].containsDecoration = true; map[0].tiles[0,0].containsLight = true; map[0].tiles[0,0].containsResource = false; } private void HandleTileVisit(int level) { HandleRenderData(BuildRenderData(level)); } private List BuildRenderData(int layerIndex) { var result = new List(); Layer layer = map[layerIndex]; layer.ClearDecorations(); for (int x = 0; x < layerSize; x++) { for (int y = 0; y < layerSize; y++) { Tile tile = layer.tiles[x, y]; result.Add(new TileRenderData { Tile = tile, MeshKey = tile.collapsedMesh, Transform = new Transform3D(Basis.Identity, tile.Position), Placeholders = tilePlaceholders[tile.collapsedMesh] }); } } if (!layer.hasContentGenerated) { DistributeTileContent(layer); layer.hasContentGenerated = true; } return result; } private void DistributeTileContent(Layer layer) { int currentDecoration = 0; int currentLight = 0; int currentResource = 0; int posX, posY; while (currentLight < layerSize * 3) { posX = rand.Next(layerSize); posY = rand.Next(layerSize); //Skip already placed lights and skip junction and gate as they do not contain lights if (layer.tiles[posX, posY].collapsedMesh == "junction" || layer.tiles[posX, posY].collapsedMesh == "gate") continue; if (layer.tiles[posX, posY].containsLight) continue; layer.tiles[posX, posY].containsLight = true; currentLight++; } while (currentDecoration < layerSize) { posX = rand.Next(layerSize); posY = rand.Next(layerSize); if (layer.tiles[posX, posY].containsDecoration) continue; layer.tiles[posX, posY].containsDecoration = true; currentDecoration++; } while (currentResource < layerSize) { posX = rand.Next(layerSize); posY = rand.Next(layerSize); if (layer.tiles[posX, posY].containsResource) continue; layer.tiles[posX, posY].containsResource = true; layer.tiles[posX, posY].resource = new GameResource(ResourceDistributor.GetResource(layer.currentResources)); layer.currentResources.Add(layer.tiles[posX, posY].resource.name); currentResource++; } } private void HandleRenderData(List renderData) { multiMeshHandler.Build(renderData); foreach (TileRenderData data in renderData) { data.Tile.SpawnContent(contentMeshes, data.Transform, data.Placeholders); } } }