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.
327 lines
11 KiB
327 lines
11 KiB
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>(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<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]);
|
|
return change;
|
|
}
|
|
private struct wave
|
|
{
|
|
public List<Tiles> 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;
|
|
}
|
|
} |