Cleaned up project with better structure.
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using static WFC;
|
||||
|
||||
public partial class Layer : Node3D
|
||||
{
|
||||
private const int MaxGenerationAttempts = 1000;
|
||||
private static readonly Vector2I NoPosition = new Vector2I(-100, -100);
|
||||
|
||||
private Node3D decorationRoot;
|
||||
public Tile[,] tiles;
|
||||
private int layerSize;
|
||||
private int level;
|
||||
private bool updateFailed = false;
|
||||
public bool hasContentGenerated = false;
|
||||
public Vector2I gateCoordinate;
|
||||
public List<string> currentResources;
|
||||
public bool isGateOpen = false;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
currentResources = new List<string>();
|
||||
decorationRoot = new Node3D
|
||||
{
|
||||
Name = "Decorations"
|
||||
};
|
||||
AddChild(decorationRoot);
|
||||
}
|
||||
|
||||
public void ClearDecorations()
|
||||
{
|
||||
foreach (Tile tile in tiles)
|
||||
{
|
||||
foreach (Node child in tile.ContentNode.GetChildren())
|
||||
{
|
||||
child.QueueFree();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetupLayer(int layerSize, int level, Dictionary<string, MeshInstance3D> tileMeshes, Vector2I collapseOrigin)
|
||||
{
|
||||
this.layerSize = layerSize;
|
||||
this.level = level;
|
||||
tiles = new Tile[layerSize, layerSize];
|
||||
|
||||
GenerateBaseStructure(tileMeshes);
|
||||
|
||||
int safetyCounter = 0;
|
||||
while (true)
|
||||
{
|
||||
if (GenerateLayer(collapseOrigin)) break;
|
||||
ResetLayer(tileMeshes);
|
||||
safetyCounter++;
|
||||
if (safetyCounter > MaxGenerationAttempts) break;
|
||||
}
|
||||
CreateTileNodes();
|
||||
}
|
||||
|
||||
private void GenerateBaseStructure(Dictionary<string, MeshInstance3D> tileMeshes)
|
||||
{
|
||||
Vector3 position;
|
||||
float offsetX;
|
||||
float offsetY = level * GameData.tileHeight * -1;
|
||||
float offsetZ;
|
||||
for (int x = 0; x < layerSize; x++)
|
||||
{
|
||||
offsetX = x * GameData.tileWidth;
|
||||
for (int y = 0; y < layerSize; y++)
|
||||
{
|
||||
offsetZ = y * GameData.tileWidth;
|
||||
position = new Vector3(offsetX, offsetY, offsetZ);
|
||||
Tile tile = new Tile();
|
||||
tile.SetMeshes(tileMeshes);
|
||||
tile.Position = position;
|
||||
tile.GridPosition = new Vector2I(x, y);
|
||||
tiles[x, y] = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateTileNodes()
|
||||
{
|
||||
foreach (Tile tile in tiles)
|
||||
{
|
||||
Node3D node = new Node3D
|
||||
{
|
||||
Position = tile.Position,
|
||||
Visible = tile.collapsedMesh != null && tile.collapsedMesh == "gate"
|
||||
};
|
||||
decorationRoot.AddChild(node);
|
||||
|
||||
tile.ContentNode = node;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetLayer(Dictionary<string, MeshInstance3D> tileMeshes)
|
||||
{
|
||||
updateFailed = false;
|
||||
|
||||
for (int x = 0; x < layerSize; x++)
|
||||
{
|
||||
for (int y = 0; y < layerSize; y++)
|
||||
{
|
||||
tiles[x, y].Reset(tileMeshes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateBorder()
|
||||
{
|
||||
for (int x = 0; x < layerSize; x++)
|
||||
{
|
||||
for (int z = 0; z < layerSize; z++)
|
||||
{
|
||||
if (x == 0 && z == 0 && level == 0) continue;
|
||||
if (!IsBorder(x, z))
|
||||
continue;
|
||||
|
||||
Tile tile = tiles[x, z];
|
||||
List<string> possibilities = GetBorderPossibilities(x, z);
|
||||
|
||||
if (possibilities.Count == 0)
|
||||
continue;
|
||||
|
||||
tile.Collapse(possibilities[GameData.rand.Next(possibilities.Count)]);
|
||||
Propagate(new Vector2I(x, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsBorder(int x, int z)
|
||||
{
|
||||
return x == 0 || z == 0 || x == layerSize - 1 || z == layerSize - 1;
|
||||
}
|
||||
|
||||
private void GenerateNecessaryTiles()
|
||||
{
|
||||
//Generate spawn only in the first layer
|
||||
if (level == 0)
|
||||
{
|
||||
tiles[0, 0].Collapse("spawn");
|
||||
Propagate(new Vector2I());
|
||||
}
|
||||
|
||||
int posX, posY;
|
||||
while (true)
|
||||
{
|
||||
posX = GameData.rand.Next(layerSize);
|
||||
posY = GameData.rand.Next(layerSize);
|
||||
|
||||
if (tiles[posX, posY].collapsedMesh != null) continue;
|
||||
if (tiles[posX, posY].tileMeshes.ContainsKey("gate"))
|
||||
{
|
||||
tiles[posX, posY].Collapse("gate");
|
||||
tiles[posX, posY].containsDecoration = true;
|
||||
gateCoordinate = new Vector2I(posX, posY);
|
||||
Propagate(gateCoordinate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool GenerateLayer(Vector2I collapseOrigin)
|
||||
{
|
||||
int safetyCounter = 0;
|
||||
GenerateBorder();
|
||||
|
||||
GenerateNecessaryTiles();
|
||||
Vector2I position = tiles[collapseOrigin.X, collapseOrigin.Y].collapsedMesh == null ? collapseOrigin : GetSmallestPossibilities();
|
||||
while (true)
|
||||
{
|
||||
string keyword = tiles[position.X, position.Y].Collapse("");
|
||||
if (keyword == "ERR") return false;
|
||||
if (keyword != "")
|
||||
{
|
||||
Propagate(position);
|
||||
if (updateFailed) break;
|
||||
position = GetSmallestPossibilities();
|
||||
if (position == NoPosition)
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
safetyCounter++;
|
||||
if (safetyCounter == layerSize * layerSize) return false;
|
||||
}
|
||||
if (updateFailed) return false;
|
||||
if (!WFC.IsMapConnected(tiles, 0.8f)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Propagate(Vector2I startPos)
|
||||
{
|
||||
Queue<Vector2I> queue = new Queue<Vector2I>();
|
||||
queue.Enqueue(startPos);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
Vector2I currentPos = queue.Dequeue();
|
||||
Tile currentTile = tiles[currentPos.X, currentPos.Y];
|
||||
|
||||
HashSet<string> currentPossibilities = currentTile.collapsedMesh != null
|
||||
? new HashSet<string> { currentTile.collapsedMesh }
|
||||
: new HashSet<string>(currentTile.tileMeshes.Keys);
|
||||
|
||||
for (int i = 0; i < offsets2D.Length; i++)
|
||||
{
|
||||
Vector2I newPos = currentPos + offsets2D[i];
|
||||
if (!InBounds(newPos, layerSize)) continue;
|
||||
|
||||
Tile neighborTile = tiles[newPos.X, newPos.Y];
|
||||
|
||||
HashSet<string> allowed = new HashSet<string>();
|
||||
|
||||
foreach (string neighborOption in neighborTile.tileMeshes.Keys)
|
||||
{
|
||||
foreach (string item in currentPossibilities)
|
||||
{
|
||||
if (WFC.CanConnect(item, neighborOption, dirs[i], false))
|
||||
{
|
||||
allowed.Add(neighborOption);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int updateCount = neighborTile.Propagate(allowed);
|
||||
|
||||
if (updateCount == int.MaxValue)
|
||||
{
|
||||
updateFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (updateCount > 0)
|
||||
{
|
||||
queue.Enqueue(newPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Vector2I GetSmallestPossibilities()
|
||||
{
|
||||
Vector2I result = NoPosition;
|
||||
int lowest = 100;
|
||||
int current;
|
||||
for (int x = 0; x < layerSize; x++)
|
||||
{
|
||||
for (int y = 0; y < layerSize; y++)
|
||||
{
|
||||
if (tiles[x, y].collapsedMesh != null) continue;
|
||||
current = tiles[x, y].tileMeshes.Count;
|
||||
if (current < lowest)
|
||||
{
|
||||
result = new Vector2I(x, y);
|
||||
lowest = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dkg0vq75koeig
|
||||
@@ -0,0 +1,23 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class LightHandler
|
||||
{
|
||||
public static List<OmniLight3D> lights = new List<OmniLight3D>();
|
||||
|
||||
public static void RedrawLights(Color color)
|
||||
{
|
||||
List<OmniLight3D> availableLights = new List<OmniLight3D>();
|
||||
|
||||
foreach (OmniLight3D light in lights)
|
||||
{
|
||||
if (GodotObject.IsInstanceValid(light))
|
||||
{
|
||||
light.LightColor = color;
|
||||
availableLights.Add(light);
|
||||
}
|
||||
}
|
||||
|
||||
lights = availableLights;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://b150nxl3cc3ck
|
||||
@@ -0,0 +1,138 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public partial class Map : PanelContainer
|
||||
{
|
||||
[Export] GridContainer grid;
|
||||
private HashSet<Tile> handledTiles = new HashSet<Tile>();
|
||||
private Dictionary<Tile, TextureRect> textureMap = new Dictionary<Tile, TextureRect>();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
grid.Columns = GameData.layerSize + 1;
|
||||
}
|
||||
|
||||
public void ShowMap()
|
||||
{
|
||||
if (!Visible) return;
|
||||
|
||||
ClearGrid();
|
||||
|
||||
Tile[,] tiles = GameData.map[GameData.currentLayer].tiles;
|
||||
int size = GameData.layerSize;
|
||||
|
||||
for (int z = -1; z < size; z++)
|
||||
{
|
||||
for (int x = -1; x < size; x++)
|
||||
{
|
||||
if (z == -1 || x == -1)
|
||||
{
|
||||
grid.AddChild(CreateHeaderLabel(x, z));
|
||||
continue;
|
||||
}
|
||||
|
||||
TextureRect texture = CreateTileTexture(tiles[x, z]);
|
||||
textureMap[tiles[x, z]] = texture;
|
||||
|
||||
if (!handledTiles.Contains(tiles[x, z]))
|
||||
{
|
||||
tiles[x, z].OnTileVisited += OnTileVisited;
|
||||
handledTiles.Add(tiles[x, z]);
|
||||
}
|
||||
|
||||
texture.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
texture.SizeFlagsVertical = SizeFlags.ExpandFill;
|
||||
texture.StretchMode = TextureRect.StretchModeEnum.Scale;
|
||||
|
||||
grid.AddChild(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearGrid()
|
||||
{
|
||||
foreach (Node node in grid.GetChildren())
|
||||
{
|
||||
grid.RemoveChild(node);
|
||||
node.QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
private Label CreateHeaderLabel(int x, int z)
|
||||
{
|
||||
Label label = new Label
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill,
|
||||
SizeFlagsVertical = SizeFlags.ExpandFill
|
||||
};
|
||||
|
||||
if (z == -1 && x == -1) label.Text = "\u2193 Z | \u2192 X";
|
||||
else if (z == -1) label.Text = x.ToString();
|
||||
else label.Text = z.ToString();
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
private TextureRect CreateTileTexture(Tile tile)
|
||||
{
|
||||
TextureRect texture = new TextureRect
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill,
|
||||
SizeFlagsVertical = SizeFlags.ExpandFill,
|
||||
StretchMode = TextureRect.StretchModeEnum.Scale
|
||||
};
|
||||
|
||||
UpdateTileTexture(tile, texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
private void OnTileVisited(object sender, EventArgs e)
|
||||
{
|
||||
Tile tile = sender as Tile;
|
||||
|
||||
if (tile == null)
|
||||
return;
|
||||
|
||||
if (textureMap.TryGetValue(tile, out TextureRect texture))
|
||||
{
|
||||
UpdateMap(tile, texture);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateMap(Tile tile, TextureRect texture)
|
||||
{
|
||||
if (!IsInstanceValid(texture)) return;
|
||||
|
||||
UpdateTileTexture(tile, texture);
|
||||
}
|
||||
|
||||
private void UpdateTileTexture(Tile tile, TextureRect texture)
|
||||
{
|
||||
if (!tile.wasVisited && !GameData.debugMode)
|
||||
{
|
||||
texture.Texture = GenerateTexture(32, new Color(0, 0, 0, 1));
|
||||
texture.TooltipText = "Not explored";
|
||||
}
|
||||
else if (tile.containsResource)
|
||||
{
|
||||
texture.Texture = ResourceDistributor.resources[tile.resource.name];
|
||||
texture.TooltipText = tile.resource.item.GetReadableName() + $"\r(X: {tile.GridPosition.X},Y: {GameData.currentLayer},Z: {tile.GridPosition.Y})";
|
||||
}
|
||||
else
|
||||
{
|
||||
texture.Texture = GenerateTexture(32, new Color(0, 0, 0, 0));
|
||||
texture.TooltipText = "";
|
||||
}
|
||||
}
|
||||
|
||||
public Texture2D GenerateTexture(int size, Color fillColor)
|
||||
{
|
||||
Image image = Image.CreateEmpty(size, size, false, Image.Format.Rgba8);
|
||||
image.Fill(fillColor);
|
||||
|
||||
return ImageTexture.CreateFromImage(image);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://fegfbcnlk8p5
|
||||
@@ -0,0 +1,45 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class MultiMeshHandler
|
||||
{
|
||||
private readonly Dictionary<string, MultiMeshInstance3D> multiMeshes;
|
||||
|
||||
public MultiMeshHandler(Dictionary<string, MultiMeshInstance3D> multiMeshes)
|
||||
{
|
||||
this.multiMeshes = multiMeshes;
|
||||
}
|
||||
|
||||
public void Build(List<TileRenderData> tiles)
|
||||
{
|
||||
foreach (MultiMeshInstance3D multiMeshInstance in multiMeshes.Values)
|
||||
{
|
||||
multiMeshInstance.Multimesh.InstanceCount = 0;
|
||||
}
|
||||
|
||||
Dictionary<string, List<Transform3D>> batches = new Dictionary<string, List<Transform3D>>();
|
||||
|
||||
foreach (TileRenderData tile in tiles)
|
||||
{
|
||||
if (!batches.ContainsKey(tile.MeshKey))
|
||||
{
|
||||
batches[tile.MeshKey] = new List<Transform3D>();
|
||||
}
|
||||
|
||||
batches[tile.MeshKey].Add(tile.Transform);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, List<Transform3D>> kvp in batches)
|
||||
{
|
||||
MultiMesh multiMesh = multiMeshes[kvp.Key].Multimesh;
|
||||
List<Transform3D> transforms = kvp.Value;
|
||||
|
||||
multiMesh.InstanceCount = transforms.Count;
|
||||
|
||||
for (int i = 0; i < transforms.Count; i++)
|
||||
{
|
||||
multiMesh.SetInstanceTransform(i, transforms[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dc0v2yndgikkw
|
||||
@@ -0,0 +1,131 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
public class Pathfinding
|
||||
{
|
||||
private static AStar3D aStar = new AStar3D();
|
||||
private static Dictionary<Vector3I, long> coordToId = new Dictionary<Vector3I, long>();
|
||||
private static Dictionary<long, Vector3I> idToCoord = new Dictionary<long, Vector3I>();
|
||||
private static long nextId = 1;
|
||||
private static Dictionary<int, (long fromId, long toId)> verticalConnections = new Dictionary<int, (long fromId, long toId)>();
|
||||
|
||||
private static long GetOrCreateId(Vector3I coord)
|
||||
{
|
||||
if (coordToId.TryGetValue(coord, out long id))
|
||||
return id;
|
||||
|
||||
id = nextId++;
|
||||
coordToId[coord] = id;
|
||||
idToCoord[id] = coord;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public static void BuildAStarGraph()
|
||||
{
|
||||
aStar.Clear();
|
||||
coordToId.Clear();
|
||||
idToCoord.Clear();
|
||||
verticalConnections.Clear();
|
||||
nextId = 1;
|
||||
|
||||
for (int y = 0; y < GameData.ruinSize; y++)
|
||||
{
|
||||
for (int x = 0; x < GameData.layerSize; x++)
|
||||
{
|
||||
for (int z = 0; z < GameData.layerSize; z++)
|
||||
{
|
||||
Vector3I coord = new Vector3I(x, y, z);
|
||||
Tile tile = GameData.map[y].tiles[x, z];
|
||||
|
||||
if (tile == null || tile.collapsedMesh == null) continue;
|
||||
|
||||
long id = GetOrCreateId(coord);
|
||||
|
||||
aStar.AddPoint(id, tile.Position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<Vector3I, long> kvp in coordToId)
|
||||
{
|
||||
Vector3I from = kvp.Key;
|
||||
long fromId = kvp.Value;
|
||||
|
||||
foreach (Vector3I offset in WFC.offsets3D)
|
||||
{
|
||||
Vector3I to = new Vector3I(
|
||||
from.X + offset.X,
|
||||
from.Y + offset.Y,
|
||||
from.Z + offset.Z
|
||||
);
|
||||
|
||||
if (!coordToId.ContainsKey(to)) continue;
|
||||
|
||||
if (!WFC.CanWalk3D(from, to)) continue;
|
||||
|
||||
long toId = coordToId[to];
|
||||
|
||||
if (from.Y != to.Y && GameData.map[from.Y].tiles[from.X, from.Z].collapsedMesh == "gate")
|
||||
{
|
||||
verticalConnections[from.Y] = (fromId, toId);
|
||||
if (GameData.map[from.Y].isGateOpen)
|
||||
{
|
||||
if (!aStar.ArePointsConnected(fromId, toId))
|
||||
{
|
||||
aStar.ConnectPoints(fromId, toId, true);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!aStar.ArePointsConnected(fromId, toId))
|
||||
{
|
||||
aStar.ConnectPoints(fromId, toId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < GameData.ruinSize; y++)
|
||||
{
|
||||
UpdateGatePoint(y, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateGatePoint(int layer, bool isOpen)
|
||||
{
|
||||
if (!verticalConnections.ContainsKey(layer)) return;
|
||||
|
||||
(long fromId, long toId) = verticalConnections[layer];
|
||||
|
||||
if (isOpen)
|
||||
{
|
||||
if (!aStar.ArePointsConnected(fromId, toId))
|
||||
{
|
||||
aStar.ConnectPoints(fromId, toId, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aStar.ArePointsConnected(fromId, toId))
|
||||
{
|
||||
aStar.DisconnectPoints(fromId, toId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Vector3> GetPath(Vector3I start, Vector3I end)
|
||||
{
|
||||
if (!coordToId.ContainsKey(start) || !coordToId.ContainsKey(end)) return new List<Vector3>();
|
||||
|
||||
long startId = coordToId[start];
|
||||
long endId = coordToId[end];
|
||||
|
||||
return new List<Vector3>(aStar.GetPointPath(startId, endId));
|
||||
}
|
||||
|
||||
public static Vector3I GetClosestStartPoint(Vector3 robotPosition)
|
||||
{
|
||||
return idToCoord[aStar.GetClosestPoint(robotPosition)];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dwya0owm8kv03
|
||||
@@ -0,0 +1,13 @@
|
||||
using Godot;
|
||||
|
||||
public class Placeholder
|
||||
{
|
||||
public string name;
|
||||
public Transform3D transform;
|
||||
|
||||
public Placeholder(string name, Transform3D transform)
|
||||
{
|
||||
this.name = name.Split("_")[0].ToLower();
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cng1pe6j20vrr
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
public class ResourceDistributor
|
||||
{
|
||||
public static Dictionary<string, Texture2D> resources = ResourceLoader.LoadResourceSymbols();
|
||||
|
||||
public static string GetResource(List<string> current)
|
||||
{
|
||||
List<string> availableResources = GetUnusedResources(current);
|
||||
if (availableResources.Count <= 0)
|
||||
{
|
||||
availableResources = new List<string>(resources.Keys);
|
||||
}
|
||||
|
||||
return availableResources[GameData.rand.Next(availableResources.Count)];
|
||||
}
|
||||
|
||||
private static List<string> GetUnusedResources(List<string> current)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
|
||||
foreach (string resource in resources.Keys)
|
||||
{
|
||||
if (!current.Contains(resource))
|
||||
{
|
||||
result.Add(resource);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://fao1lrpbrhuc
|
||||
@@ -0,0 +1,151 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public partial class Tile
|
||||
{
|
||||
public Dictionary<string, MeshInstance3D> tileMeshes;
|
||||
public string collapsedMesh;
|
||||
public Vector3 Position;
|
||||
public Vector2I GridPosition;
|
||||
public Node3D ContentNode;
|
||||
|
||||
public bool containsLight, containsDecoration, containsResource;
|
||||
public GameResource resource;
|
||||
public bool wasVisited;
|
||||
public event EventHandler OnTileVisited;
|
||||
|
||||
public void SetMeshes(Dictionary<string, MeshInstance3D> tileMeshes)
|
||||
{
|
||||
this.tileMeshes = new Dictionary<string, MeshInstance3D>(tileMeshes);
|
||||
}
|
||||
|
||||
public string Collapse(string tile)
|
||||
{
|
||||
if (collapsedMesh != null) return "";
|
||||
if (tileMeshes.Keys.Count <= 0) return "ERR";
|
||||
|
||||
collapsedMesh = (tile.Length > 0) ? tile : ChooseWeighted();
|
||||
tileMeshes.Clear();
|
||||
return collapsedMesh;
|
||||
}
|
||||
|
||||
private string ChooseWeighted()
|
||||
{
|
||||
float totalWeight = 0f;
|
||||
|
||||
foreach (string tile in tileMeshes.Keys)
|
||||
{
|
||||
totalWeight += WFC.weights[tile];
|
||||
}
|
||||
|
||||
float r = (float)(GameData.rand.NextDouble() * totalWeight);
|
||||
|
||||
float cumulative = 0f;
|
||||
|
||||
foreach (string tile in tileMeshes.Keys)
|
||||
{
|
||||
cumulative += WFC.weights[tile];
|
||||
|
||||
if (r <= cumulative)
|
||||
return tile;
|
||||
}
|
||||
|
||||
return "junction";
|
||||
}
|
||||
|
||||
public int Propagate(HashSet<string> possibleKeys)
|
||||
{
|
||||
int amountRemoved = 0;
|
||||
if (collapsedMesh != null) return 0;
|
||||
foreach (string key in tileMeshes.Keys.ToList())
|
||||
{
|
||||
if (!possibleKeys.Contains(key))
|
||||
{
|
||||
tileMeshes.Remove(key);
|
||||
amountRemoved++;
|
||||
}
|
||||
}
|
||||
if (tileMeshes.Count == 0) return int.MaxValue;
|
||||
return amountRemoved;
|
||||
}
|
||||
|
||||
public void Reset(Dictionary<string, MeshInstance3D> tileMeshes)
|
||||
{
|
||||
collapsedMesh = null;
|
||||
containsLight = false;
|
||||
containsDecoration = false;
|
||||
containsResource = false;
|
||||
resource = null;
|
||||
wasVisited = false;
|
||||
SetMeshes(tileMeshes);
|
||||
}
|
||||
|
||||
public void SpawnContent(Dictionary<string, MeshInstance3D> contentMeshes, Transform3D transform, List<Placeholder> placeholders)
|
||||
{
|
||||
foreach (Placeholder placeholder in placeholders)
|
||||
{
|
||||
if (containsLight && placeholder.name == "light") SpawnLight(contentMeshes["light"], placeholder, transform);
|
||||
else if (containsResource && placeholder.name == "resource") SpawnResource(contentMeshes["resource"], placeholder, transform);
|
||||
else if (containsDecoration && placeholder.name != "light" && placeholder.name != "resource") SpawnDecorations(contentMeshes, placeholder, transform);
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnLight(MeshInstance3D lightMesh, Placeholder placeholder, Transform3D transform)
|
||||
{
|
||||
MeshInstance3D light = new MeshInstance3D
|
||||
{
|
||||
Mesh = lightMesh.Mesh,
|
||||
Position = placeholder.transform.Origin
|
||||
};
|
||||
OmniLight3D lightSource = new OmniLight3D()
|
||||
{
|
||||
OmniAttenuation = 2f,
|
||||
LightColor = GameData.lightColor,
|
||||
ShadowEnabled = true,
|
||||
LightEnergy = 100f,
|
||||
LightIndirectEnergy = 1.5f,
|
||||
OmniRange = 20f,
|
||||
Position = placeholder.transform.Origin
|
||||
};
|
||||
lightSource.Position.MoveToward(transform.Origin, 0.1f);
|
||||
LightHandler.lights.Add(lightSource);
|
||||
light.AddChild(lightSource);
|
||||
ContentNode.AddChild(light);
|
||||
light.LookAt(transform.Origin, Vector3.Up);
|
||||
}
|
||||
|
||||
private void SpawnResource(MeshInstance3D resourceMesh, Placeholder placeholder, Transform3D transform)
|
||||
{
|
||||
MeshInstance3D resource = new MeshInstance3D
|
||||
{
|
||||
Mesh = resourceMesh.Mesh,
|
||||
Position = placeholder.transform.Origin
|
||||
};
|
||||
ContentNode.AddChild(resource);
|
||||
resource.LookAt(transform.Origin, Vector3.Up);
|
||||
}
|
||||
|
||||
private void SpawnDecorations(Dictionary<string, MeshInstance3D> contentMeshes, Placeholder placeholder, Transform3D transform)
|
||||
{
|
||||
foreach (string key in contentMeshes.Keys)
|
||||
{
|
||||
if (key.ToLower() != placeholder.name) continue;
|
||||
|
||||
MeshInstance3D decoration = new MeshInstance3D
|
||||
{
|
||||
Mesh = contentMeshes[key].Mesh,
|
||||
Position = placeholder.transform.Origin
|
||||
};
|
||||
ContentNode.AddChild(decoration);
|
||||
}
|
||||
}
|
||||
|
||||
public void VisitTile()
|
||||
{
|
||||
wasVisited = true;
|
||||
OnTileVisited?.Invoke(this, EventArgs.Empty);
|
||||
ContentNode.Visible = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://crimbrc78gxkc
|
||||
@@ -0,0 +1,10 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public struct TileRenderData
|
||||
{
|
||||
public Tile Tile;
|
||||
public string MeshKey;
|
||||
public Transform3D Transform;
|
||||
public List<Placeholder> Placeholders;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://chwhqyo4abxd4
|
||||
@@ -0,0 +1,278 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
|
||||
public class WFC
|
||||
{
|
||||
public static Dictionary<string, Dictionary<Direction, List<string>>> adjacency = new Dictionary<string, Dictionary<Direction, List<string>>>();
|
||||
public enum Direction
|
||||
{
|
||||
Backward,
|
||||
Forward,
|
||||
Left,
|
||||
Right,
|
||||
None,
|
||||
Up,
|
||||
Down
|
||||
}
|
||||
|
||||
public static readonly Direction[] dirs =
|
||||
{
|
||||
Direction.Backward,
|
||||
Direction.Forward,
|
||||
Direction.Left,
|
||||
Direction.Right,
|
||||
Direction.Up,
|
||||
Direction.Down
|
||||
};
|
||||
|
||||
public static readonly Vector2I[] offsets2D =
|
||||
{
|
||||
new Vector2I(0, -1),
|
||||
new Vector2I(0, 1),
|
||||
new Vector2I(-1, 0),
|
||||
new Vector2I(1, 0)
|
||||
};
|
||||
|
||||
public static readonly Vector3I[] offsets3D =
|
||||
{
|
||||
new Vector3I(0, 0, -1),
|
||||
new Vector3I(0, 0, 1),
|
||||
new Vector3I(-1, 0, 0),
|
||||
new Vector3I(1, 0, 0),
|
||||
new Vector3I(0, -1, 0),
|
||||
new Vector3I(0, 1, 0)
|
||||
};
|
||||
|
||||
public static Dictionary<string, HashSet<Direction>> tileConnections = new Dictionary<string, HashSet<Direction>>
|
||||
{
|
||||
["t_right"] = new HashSet<Direction> { Direction.Backward, Direction.Forward, Direction.Right, Direction.Up },
|
||||
["t_left"] = new HashSet<Direction> { Direction.Backward, Direction.Forward, Direction.Left, Direction.Up },
|
||||
["t_up"] = new HashSet<Direction> { Direction.Left, Direction.Right, Direction.Backward, Direction.Up },
|
||||
["t_down"] = new HashSet<Direction> { Direction.Left, Direction.Right, Direction.Forward, Direction.Up },
|
||||
|
||||
["end_up"] = new HashSet<Direction> { Direction.Backward, Direction.Up },
|
||||
["end_down"] = new HashSet<Direction> { Direction.Forward, Direction.Up },
|
||||
["end_left"] = new HashSet<Direction> { Direction.Left, Direction.Up },
|
||||
["end_right"] = new HashSet<Direction> { Direction.Right, Direction.Up },
|
||||
|
||||
["straight_left_right"] = new HashSet<Direction> { Direction.Left, Direction.Right, Direction.Up },
|
||||
["straight_up_down"] = new HashSet<Direction> { Direction.Backward, Direction.Forward, Direction.Up },
|
||||
|
||||
["corner_up_left"] = new HashSet<Direction> { Direction.Backward, Direction.Left, Direction.Up },
|
||||
["corner_up_right"] = new HashSet<Direction> { Direction.Backward, Direction.Right, Direction.Up },
|
||||
["corner_down_left"] = new HashSet<Direction> { Direction.Forward, Direction.Left, Direction.Up },
|
||||
["corner_down_right"] = new HashSet<Direction> { Direction.Forward, Direction.Right, Direction.Up },
|
||||
|
||||
["junction"] = new HashSet<Direction> { Direction.Backward, Direction.Forward, Direction.Left, Direction.Right, Direction.Up },
|
||||
["gate"] = new HashSet<Direction> { Direction.Backward, Direction.Forward, Direction.Left, Direction.Right, Direction.Up, Direction.Down },
|
||||
|
||||
["spawn"] = new HashSet<Direction> { Direction.Forward, Direction.Left },
|
||||
};
|
||||
|
||||
public static Dictionary<string, float> weights = new Dictionary<string, float>()
|
||||
{
|
||||
["junction"] = 3f,
|
||||
["t_up"] = 3f,
|
||||
["t_down"] = 3f,
|
||||
["t_left"] = 3f,
|
||||
["t_right"] = 3f,
|
||||
|
||||
["straight_left_right"] = 2f,
|
||||
["straight_up_down"] = 2f,
|
||||
|
||||
["corner_up_left"] = 0.7f,
|
||||
["corner_up_right"] = 0.7f,
|
||||
["corner_down_left"] = 0.7f,
|
||||
["corner_down_right"] = 0.7f,
|
||||
|
||||
["end_up"] = 0.2f,
|
||||
["end_down"] = 0.1f,
|
||||
["end_left"] = 0.2f,
|
||||
["end_right"] = 0.3f,
|
||||
|
||||
["gate"] = 0.0f,
|
||||
["spawn"] = 0.0f
|
||||
};
|
||||
|
||||
public static Direction Opposite(Direction dir)
|
||||
{
|
||||
return dir switch
|
||||
{
|
||||
Direction.Backward => Direction.Forward,
|
||||
Direction.Forward => Direction.Backward,
|
||||
Direction.Left => Direction.Right,
|
||||
Direction.Right => Direction.Left,
|
||||
Direction.Up => Direction.Down,
|
||||
Direction.Down => Direction.Up,
|
||||
_ => dir
|
||||
};
|
||||
}
|
||||
|
||||
public static bool CanConnect(string a, string b, Direction direction, bool checkWalking)
|
||||
{
|
||||
HashSet<Direction> aDirs = tileConnections[a];
|
||||
HashSet<Direction> bDirs = tileConnections[b];
|
||||
|
||||
bool aOpen = aDirs.Contains(direction);
|
||||
bool bOpen = bDirs.Contains(Opposite(direction));
|
||||
|
||||
if (checkWalking) return aOpen && bOpen;
|
||||
return aOpen == bOpen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void FillAdjacencies()
|
||||
{
|
||||
foreach (string tile in tileConnections.Keys)
|
||||
{
|
||||
adjacency[tile] = new Dictionary<Direction, List<string>>();
|
||||
|
||||
foreach (Direction dir in Enum.GetValues(typeof(Direction)))
|
||||
{
|
||||
List<string> valid = new List<string>();
|
||||
|
||||
foreach (string other in tileConnections.Keys)
|
||||
{
|
||||
if (CanConnect(tile, other, dir, false))
|
||||
valid.Add(other);
|
||||
}
|
||||
|
||||
adjacency[tile][dir] = valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsWalkable(Tile tile)
|
||||
{
|
||||
HashSet<Direction> connections = tileConnections[tile.collapsedMesh];
|
||||
return connections.Count > 0 && !connections.Contains(Direction.None);
|
||||
}
|
||||
|
||||
public static bool CanWalk(Tile[,] layer, Vector2I from, Vector2I to, Direction dir)
|
||||
{
|
||||
Tile fromTile = layer[from.X, from.Y];
|
||||
Tile toTile = layer[to.X, to.Y];
|
||||
|
||||
if (!IsWalkable(toTile))
|
||||
return false;
|
||||
|
||||
return CanConnect(fromTile.collapsedMesh, toTile.collapsedMesh, dir, true);
|
||||
}
|
||||
|
||||
public static bool CanWalk3D(Vector3I from, Vector3I to)
|
||||
{
|
||||
Tile fromTile = GameData.map[from.Y].tiles[from.X, from.Z];
|
||||
Tile toTile = GameData.map[to.Y].tiles[to.X, to.Z];
|
||||
|
||||
if (fromTile == null || toTile == null)
|
||||
return false;
|
||||
|
||||
if (from.Y != to.Y)
|
||||
{
|
||||
if (Math.Abs(from.Y - to.Y) != 1)
|
||||
return false;
|
||||
|
||||
if (from.Y > to.Y)
|
||||
{
|
||||
return toTile.collapsedMesh == "gate";
|
||||
}
|
||||
else
|
||||
{
|
||||
return fromTile.collapsedMesh == "gate";
|
||||
}
|
||||
}
|
||||
|
||||
int dx = to.X - from.X;
|
||||
int dz = to.Z - from.Z;
|
||||
|
||||
if (Math.Abs(dx) + Math.Abs(dz) != 1)
|
||||
return false;
|
||||
|
||||
Direction dir;
|
||||
|
||||
if (dx == 1) dir = Direction.Right;
|
||||
else if (dx == -1) dir = Direction.Left;
|
||||
else if (dz == 1) dir = Direction.Forward;
|
||||
else if (dz == -1) dir = Direction.Backward;
|
||||
else return false;
|
||||
|
||||
return CanWalk(
|
||||
GameData.map[from.Y].tiles,
|
||||
new Vector2I(from.X, from.Z),
|
||||
new Vector2I(to.X, to.Z),
|
||||
dir
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsMapConnected(Tile[,] layer, float accessibilityThreshhold)
|
||||
{
|
||||
bool result = false;
|
||||
HashSet<Vector2I> visited = new HashSet<Vector2I>();
|
||||
List<Vector2I> toCheck = new List<Vector2I>();
|
||||
Vector2I position;
|
||||
toCheck.Add(new Vector2I(1, 1));
|
||||
|
||||
int safetyCounter = 0;
|
||||
while (true)
|
||||
{
|
||||
if (toCheck.Count <= 0) break;
|
||||
int index = GameData.rand.Next(toCheck.Count);
|
||||
position = toCheck[index];
|
||||
toCheck[index] = toCheck[^1];
|
||||
toCheck.RemoveAt(toCheck.Count - 1);
|
||||
if (!visited.Add(position)) continue;
|
||||
for (int i = 0; i < offsets2D.Length; i++)
|
||||
{
|
||||
Vector2I next = position + offsets2D[i];
|
||||
|
||||
if (!InBounds(next, layer.GetLength(0)))
|
||||
continue;
|
||||
|
||||
if (CanWalk(layer, position, next, dirs[i]))
|
||||
{
|
||||
toCheck.Add(next);
|
||||
}
|
||||
}
|
||||
safetyCounter++;
|
||||
if (safetyCounter > layer.Length * 2) break;
|
||||
if (visited.Count >= Math.Pow(layer.GetLength(0) - 1, 2) * accessibilityThreshhold)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool InBounds(Vector2I pos, int layerSize)
|
||||
{
|
||||
return pos.X > 0 &&
|
||||
pos.Y > 0 &&
|
||||
pos.X < layerSize &&
|
||||
pos.Y < layerSize;
|
||||
}
|
||||
|
||||
public static List<string> GetBorderPossibilities(int x, int z)
|
||||
{
|
||||
bool left = x == 0;
|
||||
bool right = x == GameData.layerSize - 1;
|
||||
bool top = z == 0;
|
||||
bool bottom = z == GameData.layerSize - 1;
|
||||
|
||||
if (left && top) return new List<string> { "corner_down_right" };
|
||||
if (left && bottom) return new List<string> { "corner_up_right" };
|
||||
if (right && top) return new List<string> { "corner_down_left" };
|
||||
if (right && bottom) return new List<string> { "corner_up_left" };
|
||||
|
||||
if (top) return new List<string> { "straight_left_right", "t_down" };
|
||||
if (bottom) return new List<string> { "straight_left_right", "t_up" };
|
||||
if (left) return new List<string> { "straight_up_down", "t_right" };
|
||||
if (right) return new List<string> { "straight_up_down", "t_left" };
|
||||
|
||||
return new List<string>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://d3jw4gk5f8hhg
|
||||
@@ -0,0 +1,213 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using static GameData;
|
||||
|
||||
public partial class World : Node3D
|
||||
{
|
||||
public Dictionary<string, MeshInstance3D> tileMeshes;
|
||||
public Dictionary<string, MeshInstance3D> contentMeshes;
|
||||
public Dictionary<string, List<Placeholder>> tilePlaceholders;
|
||||
private PackedScene layerPrefab = ResourceLoader.LoadLayerPrefab();
|
||||
private Dictionary<string, MultiMeshInstance3D> multiMeshes = new Dictionary<string, MultiMeshInstance3D>();
|
||||
private Dictionary<string, Mesh> meshLibrary = new Dictionary<string, Mesh>();
|
||||
|
||||
private MultiMeshHandler multiMeshHandler;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
WFC.FillAdjacencies();
|
||||
|
||||
tileMeshes = ResourceLoader.LoadTiles();
|
||||
contentMeshes = ResourceLoader.LoadDecorations();
|
||||
|
||||
tilePlaceholders = new Dictionary<string, List<Placeholder>>();
|
||||
|
||||
foreach (KeyValuePair<string, MeshInstance3D> kvp in tileMeshes)
|
||||
{
|
||||
tilePlaceholders[kvp.Key] = new List<Placeholder>();
|
||||
|
||||
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));
|
||||
|
||||
Robot robot = ResourceLoader.LoadRobotPrefab().Instantiate<Robot>();
|
||||
robot.Name = "Bob";
|
||||
robot.Position = map[0].tiles[0, 0].Position;
|
||||
AddChild(robot);
|
||||
robots.Add(robot);
|
||||
}
|
||||
|
||||
private Dictionary<string, MultiMeshInstance3D> CreateMultiMeshes(Dictionary<string, Mesh> meshLibrary)
|
||||
{
|
||||
Dictionary<string, MultiMeshInstance3D> result = new Dictionary<string, MultiMeshInstance3D>();
|
||||
|
||||
foreach (KeyValuePair<string, Mesh> kvp in meshLibrary)
|
||||
{
|
||||
MultiMesh multiMesh = new MultiMesh
|
||||
{
|
||||
Mesh = kvp.Value,
|
||||
TransformFormat = MultiMesh.TransformFormatEnum.Transform3D
|
||||
};
|
||||
|
||||
MultiMeshInstance3D instance = new MultiMeshInstance3D
|
||||
{
|
||||
Multimesh = multiMesh
|
||||
};
|
||||
|
||||
AddChild(instance);
|
||||
|
||||
result[kvp.Key] = instance;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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 && map[currentLayer].isGateOpen) currentLayer++;
|
||||
|
||||
if (currentLayer != visibleLayer)
|
||||
{
|
||||
ShowLayer(currentLayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateWorld()
|
||||
{
|
||||
for (int layer = 0; layer < ruinSize; layer++)
|
||||
{
|
||||
Layer layerNode = layerPrefab.Instantiate<Layer>();
|
||||
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;
|
||||
}
|
||||
SetupSpawn();
|
||||
}
|
||||
|
||||
private void ShowLayer(int layer)
|
||||
{
|
||||
map[visibleLayer].ClearDecorations();
|
||||
HandleRenderData(BuildRenderData(layer));
|
||||
visibleLayer = layer;
|
||||
}
|
||||
|
||||
private void SetupSpawn()
|
||||
{
|
||||
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;
|
||||
map[0].tiles[0, 0].ContentNode.Visible = true;
|
||||
}
|
||||
|
||||
private List<TileRenderData> BuildRenderData(int layerIndex)
|
||||
{
|
||||
List<TileRenderData> result = new List<TileRenderData>();
|
||||
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);
|
||||
if (CannotContainLight(layer.tiles[posX, posY])) 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 bool CannotContainLight(Tile tile)
|
||||
{
|
||||
return tile.collapsedMesh == "junction" || tile.collapsedMesh == "gate";
|
||||
}
|
||||
|
||||
private void HandleRenderData(List<TileRenderData> renderData)
|
||||
{
|
||||
multiMeshHandler.Build(renderData);
|
||||
foreach (TileRenderData data in renderData)
|
||||
{
|
||||
data.Tile.SpawnContent(contentMeshes, data.Transform, data.Placeholders);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://br2udyi6t8yvf
|
||||
Reference in New Issue
Block a user