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.
RatAttack2D/Assets/Scripts/WFCGenerator.cs

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;
}
}