using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.Tilemaps; using System.Threading; public class WFCGenerator : MonoBehaviour { public Tiles[] tiles; public Vector2Int maxsize; public Tilemap ForeGround; public Tilemap BackGround; public bool gen; public float TimeToDraw; private Vector2Int yeat; private wave[,] waves; [SerializeField][ReadOnly]private float timer; private Thread genthread; private bool done; // Start is called before the first frame update void Start() { 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); } } timer = TimeToDraw; } void OnDisable() { genthread.Interrupt(); genthread.Abort(); } // Update is called once per frame void Update() { if(timer <= 0) { draw(); timer = TimeToDraw; } if (gen) { gen = false; genthread = new Thread(new ThreadStart(Generate)); genthread.Start(); } if(done) { draw(); done = false; } timer -= Time.deltaTime; } 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() { //get all 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); } } while (true) { //select with low ent Debug.Log("getting with low entropy"); Vector2Int wav = new Vector2Int(0, 0); int smallestent = 1000; for (int i = 0; i < waves.GetLength(0); i++) { for (int k = 0; k < waves.GetLength(1); k++) { if (waves[i, k].possible.Count < smallestent && waves[i, k].possible.Count != 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, 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]); /*foreach(var item in Pos) { Debug.Log(item.ToString()); } Thread.Sleep(1000); if(Pos.Count <= 100) { Debug.Log("finnished a run: " + Pos.Count); } else if(Pos.Count % 100 == 0) { Debug.Log("finnished a run: " + Pos.Count); }*/ return change; } private struct wave { public List possible; public Tiles selected; } [System.Serializable] public struct Tiles { public TileBase tile; [Header("False Black / True White")] public bool TopLeft; public bool TopRight; public bool BottomLeft; public bool BottomRight; } } public class ReadOnlyAttribute : PropertyAttribute { } [CustomPropertyDrawer(typeof(ReadOnlyAttribute))] public class ReadOnlyDrawer : PropertyDrawer { public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return EditorGUI.GetPropertyHeight(property, label, true); } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { GUI.enabled = false; EditorGUI.PropertyField(position, property, label, true); GUI.enabled = true; } }