Expand generated terrain with biome-driven props

This commit is contained in:
Alexander Sellite 2026-08-20 00:28:55 -04:00
parent e8888ed05a
commit 1e24fb0bfc
103 changed files with 5427 additions and 351 deletions

View file

@ -3,7 +3,9 @@ extends SceneTree
const CATALOG: TerrainChunkCatalog = preload(
"res://world/generation/chunks/terrain_chunk_catalog.tres"
)
const MATCH_TOLERANCE := 0.01
const BIOME_CATALOG: TerrainBiomeCatalog = preload(
"res://world/generation/biomes/terrain_biome_catalog.tres"
)
func _initialize() -> void:
@ -11,30 +13,34 @@ func _initialize() -> void:
func _run() -> void:
var generator := _make_generator()
root.add_child(generator)
if not generator._prepare_catalog():
generator.free()
quit(1)
return
var variants: Array[TerrainChunkVariant] = []
for definition: TerrainChunkDefinition in CATALOG.definitions:
var seen: Dictionary[String, bool] = {}
for variant: TerrainChunkVariant in TerrainChunkAnalyzer.create_variants(
definition,
CATALOG.chunk_size,
):
var signature := variant.topology_signature(0.001)
if seen.has(signature):
continue
seen[signature] = true
variants.append(variant)
variants.assign(generator._solver_variants)
print("Terrain chunk variants: %d" % variants.size())
print(
"Terrain chunk rotations: %d authored, %d distinct constraints"
% [generator._variants.size(), variants.size()]
)
for variant: TerrainChunkVariant in variants:
print("\n", variant.stable_key())
var ocean_edges := variant.rotated_edge_mask(
variant.definition.ocean_facing_edges
)
for edge_value: int in TerrainChunkTopology.Edge.values():
var edge := edge_value as TerrainChunkTopology.Edge
var matches := PackedStringArray()
for other: TerrainChunkVariant in variants:
var opposite := TerrainChunkTopology.opposite_edge(edge)
if variant.profile(edge).matches(
other.profile(opposite),
MATCH_TOLERANCE,
if generator._edges_are_compatible(
variant,
edge,
other,
opposite,
):
matches.append(
"%s.%s"
@ -44,17 +50,61 @@ func _run() -> void:
]
)
print(
" %s [%d points]: %s"
" %s%s [%d points]: %s"
% [
TerrainChunkTopology.edge_name(edge),
(
" [ocean]"
if (ocean_edges & (1 << edge_value)) != 0
else ""
),
variant.profile(edge).points.size(),
", ".join(matches) if not matches.is_empty() else "NONE",
]
)
if generator.generate():
var summary := generator._build_summary()
print(
(
"\nSeeded diagnostic layout %s "
+ "(%d backtracks, %d repeated edges):"
)
% [
str(summary["layout_fingerprint"]).substr(0, 12),
int(summary["backtracks"]),
int(summary["adjacent_repeat_edges"]),
]
)
var keys := generator.placement_keys()
for row: int in generator.grid_size.y:
var cells := PackedStringArray()
for column: int in generator.grid_size.x:
cells.append(keys[row * generator.grid_size.x + column])
print(" ", " ".join(cells))
var biomes := TerrainBiomeAssigner.assign(
BIOME_CATALOG,
generator.placement_records(),
generator.generation_seed,
)
print("\nBiome layout:")
for row: int in generator.grid_size.y:
var cells := PackedStringArray()
for column: int in generator.grid_size.x:
var biome_id: StringName = biomes.get(
Vector2i(column, row),
&"",
)
cells.append(String(biome_id).trim_prefix("biome_"))
print(" ", " ".join(cells))
generator.free()
quit(0)
func _make_generator() -> TerrainChunkGenerator:
var generator := TerrainChunkGenerator.new()
generator.catalog = CATALOG
generator.grid_size = Vector2i(5, 5)
generator.grid_size = Vector2i(7, 7)
generator.generation_seed = 13001
generator.generate_on_ready = false
generator.build_collision = false
@ -66,16 +116,9 @@ func _run() -> void:
"chunk_0002",
"chunk_0003",
"chunk_0004",
"chunk_0005",
"chunk_0006",
"chunk_0007",
]
)
root.add_child(generator)
if generator.generate():
print("\nSeeded diagnostic layout:")
var keys := generator.placement_keys()
for row: int in generator.grid_size.y:
var cells := PackedStringArray()
for column: int in generator.grid_size.x:
cells.append(keys[row * generator.grid_size.x + column])
print(" ", " ".join(cells))
generator.free()
quit(0)
return generator

View file

@ -24,10 +24,14 @@ func _unhandled_input(event: InputEvent) -> void:
func _on_generation_completed(summary: Dictionary) -> void:
_status.text = (
"Terrain generator diagnostic • seed %d%d chunks • "
+ "%d variants • %d backtracks\nR: regenerate • Esc/B: close"
+ "%d rotations / %d constraints • %d backtracks • "
+ "%d repeated edges\nlayout %s • R: regenerate • Esc/B: close"
) % [
int(summary["seed"]),
int(summary["chunk_count"]),
int(summary["variant_count"]),
int(summary["solver_variant_count"]),
int(summary["backtracks"]),
int(summary["adjacent_repeat_edges"]),
str(summary["layout_fingerprint"]).substr(0, 12),
]

View file

@ -21,12 +21,12 @@ shadow_enabled = true
[node name="TerrainChunkGenerator" type="Node3D" parent="."]
script = ExtResource("2_generator")
catalog = ExtResource("3_catalog")
grid_size = Vector2i(5, 5)
grid_size = Vector2i(7, 7)
generation_seed = 13001
build_collision = true
show_chunk_labels = false
force_center_chunk_id = &"chunk_spawn"
required_chunk_ids = PackedStringArray("chunk_spawn", "chunk_0001", "chunk_0002", "chunk_0003", "chunk_0004")
required_chunk_ids = PackedStringArray("chunk_spawn", "chunk_0001", "chunk_0002", "chunk_0003", "chunk_0004", "chunk_0005", "chunk_0006", "chunk_0007")
[node name="Player" parent="." instance=ExtResource("4_player")]
position = Vector3(0, 0.3, 0)