using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Tilemaps; using System.Threading; public class WFCGenerator : MonoBehaviour { public Tiles[] tiles; public Vector2Int maxsize; public Tilemap ForeGround; public bool gen; private Vector2Int yeat; private wave[,] waves; private Thread genthread; private bool done; void Start() { genthread = new Thread(new ThreadStart(Generate)); } void OnDisable() { genthread.Interrupt(); genthread.Abort(); } void Update() { if (gen) { gen = false; genthread = new Thread(new ThreadStart(Generate)); genthread.Start(); } if (genthread.ThreadState == ThreadState.Stopped && done) { done = false; draw(); } } private void NewMap() { waves = new wave[maxsize.x, maxsize.y]; for (int i = 0; i < waves.GetLength(0); i++) { for (int k = 0; k < waves.GetLength(1); k++) { waves[i, k].possible = new List(tiles); } } for(int i = 0; i < tiles.Length; i++) { tiles[i].Globalweight = 0; } } private void draw() { for (int i = 0; i < waves.GetLength(0); i++) { for (int k = 0; k < waves.GetLength(1); k++) { if (waves[i, k].possible.Count == 0) { ForeGround.SetTile(new Vector3Int(-i, -k, 0), waves[i, k].selected.tile); } } } } private void Generate() { while (true) { //select with low ent Debug.Log("getting with low entropy"); Vector2Int wav = new Vector2Int(0, 0); float smallestent = 1000; for (int runs = 0; runs < 2; runs++) { for (int i = 0; i < waves.GetLength(0); i++) { for (int k = 0; k < waves.GetLength(1); k++) { if(runs == 0) { float total = 0; float logtotal = 0; foreach(var item in waves[i, k].possible) { total += item.weight; logtotal += Mathf.Log(item.weight, 2); } waves[i, k].entropy = Mathf.Log(total, 2) - (logtotal/total); continue; } if (waves[i, k].entropy < smallestent && waves[i, k].entropy != 0) { smallestent = waves[i, k].possible.Count; wav = new Vector2Int(i, k); } } } } //set down Debug.Log("selecting random low entropy"); System.Random r = new System.Random(); waves[wav.x, wav.y].selected = waves[wav.x, wav.y].possible[r.Next(0, (int)smallestent)]; waves[wav.x, wav.y].possible.Clear(); //propagate Debug.Log("started propagation"); List Pos = new List(); Pos.Add(wav); while (true) { if (Pos.Count == 0) { break; } propagate(Pos); } int check = 0; foreach (var item in waves) { check += item.possible.Count; } if (check == 0) { break; } } //draw done = true; } private bool propagate(List Pos) { bool change = false; //get working List t = new List(); if (waves[Pos[0].x, Pos[0].y].possible.Count > 0) { t = waves[Pos[0].x, Pos[0].y].possible; } else { t.Add(waves[Pos[0].x, Pos[0].y].selected); } //checking the one to the left if (Pos[0].x - 1 >= 0) { if (waves[Pos[0].x - 1, Pos[0].y].possible.Count > 0) { List yeat = new List(); bool gChange = false; foreach (var item in waves[Pos[0].x - 1, Pos[0].y].possible) { bool nomatch = true; foreach (var it in t) { if (item.TopRight == it.TopLeft && item.BottomRight == it.BottomLeft) { nomatch = false; break; } } if (nomatch) { yeat.Add(item); } } foreach (var item in yeat) { waves[Pos[0].x - 1, Pos[0].y].possible.Remove(item); change = true; gChange = true; } if (waves[Pos[0].x - 1, Pos[0].y].possible.Count == 1) { waves[Pos[0].x - 1, Pos[0].y].selected = waves[Pos[0].x - 1, Pos[0].y].possible[0]; waves[Pos[0].x - 1, Pos[0].y].possible.Clear(); } if (gChange) { Pos.Add(new Vector2Int(Pos[0].x - 1, Pos[0].y)); } } } //checking the one above if (Pos[0].y - 1 >= 0) { if (waves[Pos[0].x, Pos[0].y - 1].possible.Count > 0) { List yeat = new List(); bool gChange = false; foreach (var item in waves[Pos[0].x, Pos[0].y - 1].possible) { bool nomatch = true; foreach (var it in t) { if (item.BottomRight == it.TopRight && item.BottomLeft == it.TopLeft) { nomatch = false; break; } } if (nomatch) { yeat.Add(item); } } foreach (var item in yeat) { waves[Pos[0].x, Pos[0].y - 1].possible.Remove(item); change = true; gChange = true; } if (waves[Pos[0].x, Pos[0].y - 1].possible.Count == 1) { waves[Pos[0].x, Pos[0].y - 1].selected = waves[Pos[0].x, Pos[0].y - 1].possible[0]; waves[Pos[0].x, Pos[0].y - 1].possible.Clear(); } if (gChange) { Pos.Add(new Vector2Int(Pos[0].x, Pos[0].y - 1)); } } } //checking the one to the right if (Pos[0].x + 1 < waves.GetLength(0)) { if (waves[Pos[0].x + 1, Pos[0].y].possible.Count > 0) { List yeat = new List(); bool gChange = false; foreach (var item in waves[Pos[0].x + 1, Pos[0].y].possible) { bool nomatch = true; foreach (var it in t) { if (item.TopRight == it.TopLeft && item.BottomRight == it.BottomLeft) { nomatch = false; break; } } if (nomatch) { yeat.Add(item); } } foreach (var item in yeat) { waves[Pos[0].x + 1, Pos[0].y].possible.Remove(item); change = true; gChange = true; } if (waves[Pos[0].x + 1, Pos[0].y].possible.Count == 1) { waves[Pos[0].x + 1, Pos[0].y].selected = waves[Pos[0].x + 1, Pos[0].y].possible[0]; waves[Pos[0].x + 1, Pos[0].y].possible.Clear(); } if (gChange) { Pos.Add(new Vector2Int(Pos[0].x + 1, Pos[0].y)); } } } //checking the one under if (Pos[0].y + 1 < waves.GetLength(1)) { if (waves[Pos[0].x, Pos[0].y + 1].possible.Count > 0) { List yeat = new List(); bool gChange = false; foreach (var item in waves[Pos[0].x, Pos[0].y + 1].possible) { bool nomatch = true; foreach (var it in t) { if (item.TopRight == it.BottomRight && item.TopLeft == it.BottomLeft) { nomatch = false; break; } } if (nomatch) { yeat.Add(item); } } foreach (var item in yeat) { waves[Pos[0].x, Pos[0].y + 1].possible.Remove(item); change = true; gChange = true; } if (waves[Pos[0].x, Pos[0].y + 1].possible.Count == 1) { waves[Pos[0].x, Pos[0].y + 1].selected = waves[Pos[0].x, Pos[0].y + 1].possible[0]; waves[Pos[0].x, Pos[0].y + 1].possible.Clear(); } if (gChange) { Pos.Add(new Vector2Int(Pos[0].x, Pos[0].y + 1)); } } } Pos.Remove(Pos[0]); return change; } private struct wave { public List possible; public Tiles selected; public float entropy; } [System.Serializable] public struct Tiles { public TileBase tile; public float weight; [Header("False Black / True White")] public bool TopLeft; public bool TopRight; public bool BottomLeft; public bool BottomRight; [System.NonSerialized]public float Globalweight; } }