It's much nicer to code with now
This commit is contained in:
@@ -12,20 +12,26 @@ func _reset_entropy() -> void:
|
||||
entropy_total.clear()
|
||||
entropy_total.resize(Chunk.CHUNK_WIDTH * Chunk.CHUNK_HEIGHT)
|
||||
entropy_total.fill(-1)
|
||||
|
||||
|
||||
func _update_entropy(chunk: Chunk, samples: Array[PackedInt32Array]) -> void:
|
||||
#iterate over indeterminate tiles to find their valid neighbours
|
||||
for x in range(Chunk.CHUNK_WIDTH):
|
||||
for y in range((Chunk.CHUNK_HEIGHT)):
|
||||
if entropy_total[y * Chunk.CHUNK_WIDTH + x] < 0: #There's some excess multiplication in this code, but I want to get it right first
|
||||
entropy_valid[y * Chunk.CHUNK_WIDTH + x] = _find_valid_samples_at(chunk, x, y, samples) #this overrides any pre-existing cached data
|
||||
entropy_total[y * Chunk.CHUNK_WIDTH + x] = entropy_valid[y * Chunk.CHUNK_WIDTH + x].size() #the entropy is stored separately or faster processing
|
||||
var index: int = y * Chunk.CHUNK_WIDTH + x #reduce number crunching
|
||||
|
||||
if chunk.data[index] > 0: #if the tile is already set, ignore
|
||||
entropy_total[index] = 0
|
||||
|
||||
if entropy_total[index] < 0:
|
||||
entropy_valid[index] = _find_valid_samples_at(chunk, x, y, samples) #this overrides any pre-existing cached data
|
||||
entropy_total[index] = entropy_valid[index].size() #the entropy is stored separately for faster processing
|
||||
|
||||
func _clear_entropy_at(index: int) -> void:
|
||||
func _zero_entropy_at(chunk: Chunk, index: int) -> void:
|
||||
var clear_at := func (dx: int, dy: int) -> void:
|
||||
var check = index + (dy * Chunk.CHUNK_WIDTH) + (dx)
|
||||
if check >= 0 and check < Chunk.CHUNK_WIDTH * Chunk.CHUNK_HEIGHT:
|
||||
if entropy_total[check] > 0: entropy_total[check] = -1 #unset surrounding tiles
|
||||
var idx = index + (dy * Chunk.CHUNK_WIDTH) + (dx)
|
||||
if idx >= 0 and idx < Chunk.CHUNK_WIDTH * Chunk.CHUNK_HEIGHT:
|
||||
if entropy_total[idx] > 0 and chunk.data[idx] <= 0: entropy_total[idx] = -1 #unset surrounding tiles
|
||||
|
||||
clear_at.call(-1, -1)
|
||||
clear_at.call( 0, -1)
|
||||
clear_at.call( 1, -1)
|
||||
@@ -40,16 +46,18 @@ func _clear_entropy_at(index: int) -> void:
|
||||
func generate_chunk_at(_x: int, _y: int, chunk_array: Array[Chunk], samples: Array[PackedInt32Array]) -> Chunk:
|
||||
var chunk: Chunk = Chunk.new(_x, _y)
|
||||
_reset_entropy()
|
||||
#chunk.data[0] = 1 #DEBUG: seed
|
||||
_update_entropy(chunk, samples)
|
||||
|
||||
while true:
|
||||
while true: #TODO: would a floodfill approach work better?
|
||||
var index = _find_lowest_entropy_tile_index()
|
||||
if index < 0: break #none found, finished
|
||||
|
||||
print(index, ":", entropy_total[index])
|
||||
|
||||
var s: PackedInt32Array = entropy_valid[index].pick_random()
|
||||
chunk.data[index] = s[4]
|
||||
|
||||
_clear_entropy_at(index)
|
||||
_zero_entropy_at(chunk, index)
|
||||
_update_entropy(chunk, samples)
|
||||
|
||||
chunk_array.append(chunk)
|
||||
@@ -59,18 +67,25 @@ func generate_chunk_at(_x: int, _y: int, chunk_array: Array[Chunk], samples: Arr
|
||||
func _find_lowest_entropy_tile_index() -> int:
|
||||
#find the lowest-entropy tile
|
||||
var lowest: int = -1
|
||||
var lowest_list: Array[int] #smooth out order bias
|
||||
|
||||
for i in range(Chunk.CHUNK_WIDTH * Chunk.CHUNK_HEIGHT):
|
||||
if lowest < 0:
|
||||
if entropy_total[i] <= 0: continue #no options
|
||||
lowest = i
|
||||
lowest_list = [i]
|
||||
continue
|
||||
|
||||
if entropy_total[i] > 0 and entropy_total[i] < entropy_total[lowest]:
|
||||
lowest = i
|
||||
|
||||
#actually update the lowest found
|
||||
if entropy_total[i] > 0:
|
||||
if entropy_total[i] < entropy_total[lowest]:
|
||||
lowest = i
|
||||
lowest_list = [i]
|
||||
elif entropy_total[i] == entropy_total[lowest]:
|
||||
lowest_list.append(i)
|
||||
|
||||
#finished
|
||||
return lowest
|
||||
return lowest_list.pick_random() if lowest_list.size() > 0 else lowest
|
||||
|
||||
func _find_valid_samples_at(chunk: Chunk, tile_x: int, tile_y: int, _samples: Array[PackedInt32Array]) -> Array[PackedInt32Array]:
|
||||
var valid: Array[PackedInt32Array] = []
|
||||
|
||||
63
wfc/rulesets.gd
Normal file
63
wfc/rulesets.gd
Normal file
@@ -0,0 +1,63 @@
|
||||
class_name Rulesets extends Object
|
||||
## These rulesets are loaded from a file and return samples for the generator
|
||||
|
||||
## Different rulesets can have different file dimensions
|
||||
var _size: Vector2i = Vector2i.ZERO
|
||||
|
||||
static func load_samples(filename: String) -> Array[PackedInt32Array]:
|
||||
var obj: Rulesets = Rulesets.new()
|
||||
var ruleset: PackedInt32Array = obj._load_ruleset_file(filename)
|
||||
var samples: Array[PackedInt32Array] = obj._parse_ruleset_to_samples(ruleset)
|
||||
return samples
|
||||
|
||||
## Read the png file, and parse it to a useable ruleset
|
||||
func _load_ruleset_file(filename: String) -> PackedInt32Array:
|
||||
var img: Image = Image.load_from_file(filename)
|
||||
|
||||
img.decompress()
|
||||
_size = img.get_size()
|
||||
|
||||
var png: PackedByteArray = img.get_data()
|
||||
var hex: PackedInt32Array = []
|
||||
|
||||
@warning_ignore("integer_division")
|
||||
var hex_size: int = (png.size() / 3)
|
||||
hex.resize(hex_size)
|
||||
|
||||
for i in range(hex_size): #using RGB8 format
|
||||
var rgb8: int = (png[i * 3] << 16) | (png[i * 3 + 1] << 8) | (png[i * 3 + 2] << 0)
|
||||
match rgb8: #BUGFIX: remapped RGB to values the tilemap can handle
|
||||
0x000000: hex[i] = 1
|
||||
0xFF0000: hex[i] = 2
|
||||
0x00FF00: hex[i] = 3
|
||||
0x0000FF: hex[i] = 4
|
||||
_: hex[i] = 1
|
||||
|
||||
return hex
|
||||
|
||||
## Convert the raw hexcodes to usable WFC samples
|
||||
func _parse_ruleset_to_samples(ruleset: PackedInt32Array) -> Array[PackedInt32Array]:
|
||||
#wrapped in a custom container type
|
||||
var samples: Set = Set.new()
|
||||
|
||||
for x in range(1, _size.x-1):
|
||||
for y in range(1, _size.y-1):
|
||||
var sample: PackedInt32Array = [
|
||||
ruleset[(y -1) * _size.x + (x -1)],
|
||||
ruleset[(y -1) * _size.x + (x )],
|
||||
ruleset[(y -1) * _size.x + (x +1)],
|
||||
|
||||
ruleset[(y ) * _size.x + (x -1)],
|
||||
ruleset[(y ) * _size.x + (x )],
|
||||
ruleset[(y ) * _size.x + (x +1)],
|
||||
|
||||
ruleset[(y +1) * _size.x + (x -1)],
|
||||
ruleset[(y +1) * _size.x + (x )],
|
||||
ruleset[(y +1) * _size.x + (x +1)],
|
||||
]
|
||||
|
||||
samples.add(sample)
|
||||
|
||||
var result: Array[PackedInt32Array] = []
|
||||
result.assign(samples.elements())
|
||||
return result
|
||||
1
wfc/rulesets.gd.uid
Normal file
1
wfc/rulesets.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cb6akqmmarmxa
|
||||
Reference in New Issue
Block a user