You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
11 KiB
360 lines
11 KiB
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>(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>(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<Vector2Int> Pos = new List<Vector2Int>();
|
|
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<Vector2Int> Pos)
|
|
{
|
|
bool change = false;
|
|
//get working
|
|
List<Tiles> t = new List<Tiles>();
|
|
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<Tiles> yeat = new List<Tiles>();
|
|
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<Tiles> yeat = new List<Tiles>();
|
|
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<Tiles> yeat = new List<Tiles>();
|
|
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<Tiles> yeat = new List<Tiles>();
|
|
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<Tiles> 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;
|
|
}
|
|
} |