Naive WFC kind of working

This commit is contained in:
2026-01-07 17:40:58 +11:00
commit 7206c1b038
15 changed files with 274 additions and 0 deletions

31
wfc/chunk.gd Normal file
View File

@@ -0,0 +1,31 @@
class_name Chunk extends Object
## A Chunk of map data and bundled metadata, always aligned to CHUNK_WIDTH and CHUNK_HEIGHT
## The default data values are 0, which means "NOT SET"
## Chunks can be partially unset, to allow for prefabs
## Any values of -1 are "NOT VALID"
const CHUNK_WIDTH: int = 16
const CHUNK_HEIGHT: int = 16
var data: PackedInt32Array
var x: int
var y: int
func _init(_x: int, _y: int):
assert(_x % CHUNK_WIDTH == 0)
assert(_y % CHUNK_HEIGHT == 0)
x = _x
y = _y
data = PackedInt32Array()
data.resize(CHUNK_WIDTH * CHUNK_HEIGHT)
data.fill(0)
func get_tile(tile_x: int, tile_y: int) -> int:
if tile_x < 0 or tile_y < 0 or tile_x >= CHUNK_WIDTH or tile_y >= CHUNK_HEIGHT: return -1
return data[tile_y * CHUNK_WIDTH + tile_x]
func set_tile(tile_x: int, tile_y: int, value: int) -> int:
assert(value > 0) #do NOT clear a tile with this function
if tile_x < 0 or tile_y < 0 or tile_x >= CHUNK_WIDTH or tile_y >= CHUNK_HEIGHT: return -1
data[tile_y * CHUNK_WIDTH + tile_x] = value
return value

1
wfc/chunk.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://due7w7hripbuk

52
wfc/generator.gd Normal file
View File

@@ -0,0 +1,52 @@
extends Node
## The generator works with pure numbers, you'll need something else to convert it to actual tiles
## Makes a new chunk, derived from the given WFC samples
func generate_chunk_at(_x: int, _y: int, _chunk_array: Array[Chunk], _samples: Array[PackedInt32Array]) -> Chunk:
#TODO: fix the chunk-edges
var chunk: Chunk = Chunk.new(_x, _y)
var latch: int = 1
while latch:
latch = 0 #if set to true, the generator needs another pass
#iterate over unset tiles with valid neighbours
for x in range(Chunk.CHUNK_WIDTH):
for y in range((Chunk.CHUNK_HEIGHT)):
if chunk.data[y * Chunk.CHUNK_HEIGHT + x] == 0: #direct access, to skip extra checks
#TODO: convert this to the low-entropy method
if _set_tile_from_samples(chunk, x, y, _samples) > 0:
latch += 1
print("latch: ", latch)
print(chunk.data)
_chunk_array.append(chunk)
return chunk
## Returns the value set, or -1 if no options found
func _set_tile_from_samples(chunk: Chunk, tile_x: int, tile_y: int, _samples: Array[PackedInt32Array]) -> int:
var valid: Array[PackedInt32Array] = []
#use a lambda for easy reading below
var compare := func (tile_value: int, sample: int) -> bool:
return tile_value <= 0 or tile_value == sample
#find all valid samples
for sample in _samples:
if !compare.call(chunk.get_tile(tile_x -1, tile_y -1), sample[0]): continue
if !compare.call(chunk.get_tile(tile_x , tile_y -1), sample[1]): continue
if !compare.call(chunk.get_tile(tile_x +1, tile_y -1), sample[2]): continue
if !compare.call(chunk.get_tile(tile_x -1, tile_y ), sample[3]): continue
# //
if !compare.call(chunk.get_tile(tile_x +1, tile_y ), sample[5]): continue
if !compare.call(chunk.get_tile(tile_x -1, tile_y +1), sample[6]): continue
if !compare.call(chunk.get_tile(tile_x , tile_y +1), sample[7]): continue
if !compare.call(chunk.get_tile(tile_x +1, tile_y +1), sample[8]): continue
valid.append(sample)
print("Valid samples: ", valid.size())
if valid.size() <= 0: return -1
var s = valid.pick_random()
#set the tile to the randomly selected value
chunk.set_tile(tile_x, tile_y, s[4])
return s[4]

1
wfc/generator.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://bf6phxhnvh0ul