add uniqueness property to chunk and manage it on biome generator
This commit is contained in:
@@ -7,6 +7,8 @@ const CHUNK_TYPE_CURVED_TRACK: int = 2
|
|||||||
const CHUNK_GENERATION_STEPS_PER_FRAME: int = 2
|
const CHUNK_GENERATION_STEPS_PER_FRAME: int = 2
|
||||||
const CHUNK_CLEANUP_STEPS_PER_FRAME: int = 4
|
const CHUNK_CLEANUP_STEPS_PER_FRAME: int = 4
|
||||||
const LAMPPOST_WIRE_STEPS_PER_FRAME: int = 1
|
const LAMPPOST_WIRE_STEPS_PER_FRAME: int = 1
|
||||||
|
|
||||||
|
const MAX_CHUNK_UNIQUENESS: int = 5
|
||||||
const RAILWAY_SCENE_DIRECTORY: String = "res://tgcc/chunk/railway/scene"
|
const RAILWAY_SCENE_DIRECTORY: String = "res://tgcc/chunk/railway/scene"
|
||||||
const RIVER_SIDE_ORDER: Array[String] = ["north", "est", "south", "west"]
|
const RIVER_SIDE_ORDER: Array[String] = ["north", "est", "south", "west"]
|
||||||
const RIVER_DIRECTIONS: Dictionary = {
|
const RIVER_DIRECTIONS: Dictionary = {
|
||||||
@@ -48,7 +50,6 @@ var pending_generation_cells: Array[Vector2i] = []
|
|||||||
var pending_cleanup_cells: Array[Vector2i] = []
|
var pending_cleanup_cells: Array[Vector2i] = []
|
||||||
var pending_wire_cells: Array[Vector2i] = []
|
var pending_wire_cells: Array[Vector2i] = []
|
||||||
var pending_wire_lookup: Dictionary = {}
|
var pending_wire_lookup: Dictionary = {}
|
||||||
var pending_radar_update: bool = false
|
|
||||||
var rail_chunk_catalogue: Dictionary = {}
|
var rail_chunk_catalogue: Dictionary = {}
|
||||||
|
|
||||||
var manual_biome: Biome = null
|
var manual_biome: Biome = null
|
||||||
@@ -125,16 +126,12 @@ func _destroy_and_regenrate_world() -> void:
|
|||||||
var train_pos = rail_path.train_instance.global_position
|
var train_pos = rail_path.train_instance.global_position
|
||||||
var current_pos = Vector2i(roundi(train_pos.x / chunk_size), roundi(train_pos.z / chunk_size))
|
var current_pos = Vector2i(roundi(train_pos.x / chunk_size), roundi(train_pos.z / chunk_size))
|
||||||
_refresh_world(current_pos)
|
_refresh_world(current_pos)
|
||||||
pending_radar_update = true
|
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
_drain_cleanup_queue()
|
_drain_cleanup_queue()
|
||||||
_drain_generation_queue()
|
_drain_generation_queue()
|
||||||
_drain_wire_queue()
|
_drain_wire_queue()
|
||||||
|
|
||||||
if pending_radar_update:
|
|
||||||
pending_radar_update = false
|
|
||||||
|
|
||||||
func _physics_process(_delta: float) -> void:
|
func _physics_process(_delta: float) -> void:
|
||||||
if rail_path == null or rail_path.train_instance == null: return
|
if rail_path == null or rail_path.train_instance == null: return
|
||||||
|
|
||||||
@@ -146,7 +143,6 @@ func _physics_process(_delta: float) -> void:
|
|||||||
if current_pos != last_pos_train:
|
if current_pos != last_pos_train:
|
||||||
last_pos_train = current_pos
|
last_pos_train = current_pos
|
||||||
_refresh_world(current_pos)
|
_refresh_world(current_pos)
|
||||||
pending_radar_update = true
|
|
||||||
|
|
||||||
func collect_all_chunkinfo(root: Node, list: Array[Node]) -> void:
|
func collect_all_chunkinfo(root: Node, list: Array[Node]) -> void:
|
||||||
if root == null: return
|
if root == null: return
|
||||||
@@ -239,6 +235,7 @@ func _get_chunk_scene_metadata(scene: PackedScene) -> Dictionary:
|
|||||||
"info_path": info_path,
|
"info_path": info_path,
|
||||||
"rotations": rotations,
|
"rotations": rotations,
|
||||||
"has_lamppost": "have_lamppost" in info_node and info_node.have_lamppost,
|
"has_lamppost": "have_lamppost" in info_node and info_node.have_lamppost,
|
||||||
|
"uniqueness": _get_chunk_uniqueness_from_info(info_node),
|
||||||
}
|
}
|
||||||
preview_chunk.queue_free()
|
preview_chunk.queue_free()
|
||||||
chunk_candidate_cache[key] = metadata
|
chunk_candidate_cache[key] = metadata
|
||||||
@@ -273,7 +270,6 @@ func _clear_pending_world_work() -> void:
|
|||||||
pending_cleanup_cells.clear()
|
pending_cleanup_cells.clear()
|
||||||
pending_wire_cells.clear()
|
pending_wire_cells.clear()
|
||||||
pending_wire_lookup.clear()
|
pending_wire_lookup.clear()
|
||||||
pending_radar_update = false
|
|
||||||
|
|
||||||
func _collect_replaceable_rail_chunks(root: Node, result: Array[Node3D]) -> void:
|
func _collect_replaceable_rail_chunks(root: Node, result: Array[Node3D]) -> void:
|
||||||
if root == null:
|
if root == null:
|
||||||
@@ -470,6 +466,54 @@ func _get_procedural_biome_name(value: float) -> String:
|
|||||||
var index = clamp(int(normalized_value * biome_list.size()), 0, biome_list.size() - 1)
|
var index = clamp(int(normalized_value * biome_list.size()), 0, biome_list.size() - 1)
|
||||||
return biome_list[index].name
|
return biome_list[index].name
|
||||||
|
|
||||||
|
func _get_chunk_uniqueness_from_info(info_node: Node) -> int:
|
||||||
|
if info_node != null and "uniqueness" in info_node:
|
||||||
|
return clampi(info_node.uniqueness, 0, MAX_CHUNK_UNIQUENESS)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
func _has_nearby_unique_chunk(grid_pos: Vector2i, uniqueness: int) -> bool:
|
||||||
|
if uniqueness <= 0:
|
||||||
|
return false
|
||||||
|
|
||||||
|
for nearby_pos in board.keys():
|
||||||
|
var nearby_uniqueness = int(board[nearby_pos].get("uniqueness", 0))
|
||||||
|
if nearby_uniqueness <= 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var min_distance = maxi(uniqueness, nearby_uniqueness)
|
||||||
|
var dist_x = abs(nearby_pos.x - grid_pos.x)
|
||||||
|
var dist_z = abs(nearby_pos.y - grid_pos.y)
|
||||||
|
if dist_x <= min_distance and dist_z <= min_distance:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _get_uniqueness_pick_weight(uniqueness: int) -> float:
|
||||||
|
return 1.0 / pow(float(uniqueness + 1), 2.0)
|
||||||
|
|
||||||
|
func _pick_weighted_candidate(candidates: Array) -> Dictionary:
|
||||||
|
var total_weight = 0.0
|
||||||
|
for candidate in candidates:
|
||||||
|
total_weight += candidate.weight
|
||||||
|
|
||||||
|
if total_weight <= 0.0:
|
||||||
|
return candidates.pick_random()
|
||||||
|
|
||||||
|
var target_weight = randf() * total_weight
|
||||||
|
var current_weight = 0.0
|
||||||
|
for candidate in candidates:
|
||||||
|
current_weight += candidate.weight
|
||||||
|
if current_weight >= target_weight:
|
||||||
|
return candidate
|
||||||
|
return candidates.back()
|
||||||
|
|
||||||
|
func _pick_backup_scene(zone_catalogue: Array[PackedScene], grid_pos: Vector2i) -> PackedScene:
|
||||||
|
for scene in zone_catalogue:
|
||||||
|
var metadata = _get_chunk_scene_metadata(scene)
|
||||||
|
var uniqueness = int(metadata.get("uniqueness", 0))
|
||||||
|
if not _has_nearby_unique_chunk(grid_pos, uniqueness):
|
||||||
|
return scene
|
||||||
|
return zone_catalogue[0]
|
||||||
|
|
||||||
func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
|
func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
|
||||||
if board.has(grid_pos): return true
|
if board.has(grid_pos): return true
|
||||||
|
|
||||||
@@ -517,6 +561,7 @@ func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
|
|||||||
var river_exit_found = {"north": false, "est": false, "south": false, "west": false}
|
var river_exit_found = {"north": false, "est": false, "south": false, "west": false}
|
||||||
var height_found = {"north": 0, "est": 0, "south": 0, "west": 0}
|
var height_found = {"north": 0, "est": 0, "south": 0, "west": 0}
|
||||||
var have_lamppost = false
|
var have_lamppost = false
|
||||||
|
var uniqueness = 0
|
||||||
|
|
||||||
#Get node info
|
#Get node info
|
||||||
if right_info_node != null:
|
if right_info_node != null:
|
||||||
@@ -530,6 +575,8 @@ func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
|
|||||||
if "have_lamppost" in right_info_node:
|
if "have_lamppost" in right_info_node:
|
||||||
have_lamppost = right_info_node.have_lamppost
|
have_lamppost = right_info_node.have_lamppost
|
||||||
|
|
||||||
|
uniqueness = _get_chunk_uniqueness_from_info(right_info_node)
|
||||||
|
|
||||||
#Add piece to the grid
|
#Add piece to the grid
|
||||||
board[grid_pos] = {
|
board[grid_pos] = {
|
||||||
"type": "obstacle",
|
"type": "obstacle",
|
||||||
@@ -538,7 +585,8 @@ func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
|
|||||||
"heights": height_found,
|
"heights": height_found,
|
||||||
"node": root_chunk,
|
"node": root_chunk,
|
||||||
"info": right_info_node,
|
"info": right_info_node,
|
||||||
"have_lamppost": have_lamppost
|
"have_lamppost": have_lamppost,
|
||||||
|
"uniqueness": uniqueness
|
||||||
}
|
}
|
||||||
|
|
||||||
if have_lamppost:
|
if have_lamppost:
|
||||||
@@ -579,6 +627,9 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
|||||||
var u_conn = data["connections"]
|
var u_conn = data["connections"]
|
||||||
var u_river_conn = data["river_connections"]
|
var u_river_conn = data["river_connections"]
|
||||||
var u_height = data["heights"]
|
var u_height = data["heights"]
|
||||||
|
var uniqueness = int(metadata.get("uniqueness", 0))
|
||||||
|
if _has_nearby_unique_chunk(grid_pos, uniqueness):
|
||||||
|
continue
|
||||||
|
|
||||||
var match_conn_n = (req_conn_north == -1) or ((req_conn_north == 1) == u_conn["north"])
|
var match_conn_n = (req_conn_north == -1) or ((req_conn_north == 1) == u_conn["north"])
|
||||||
var match_conn_e = (req_conn_est == -1) or ((req_conn_est == 1) == u_conn["est"])
|
var match_conn_e = (req_conn_est == -1) or ((req_conn_est == 1) == u_conn["est"])
|
||||||
@@ -607,7 +658,14 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
|||||||
if req_height_south == -1 and u_height["south"] == height_target: score += 1
|
if req_height_south == -1 and u_height["south"] == height_target: score += 1
|
||||||
if req_height_west == -1 and u_height["west"] == height_target: score += 1
|
if req_height_west == -1 and u_height["west"] == height_target: score += 1
|
||||||
|
|
||||||
valid_candidates.append({"scene": scene, "rotation": rot, "data": data, "score": score})
|
valid_candidates.append({
|
||||||
|
"scene": scene,
|
||||||
|
"rotation": rot,
|
||||||
|
"data": data,
|
||||||
|
"score": score,
|
||||||
|
"weight": _get_uniqueness_pick_weight(uniqueness),
|
||||||
|
"uniqueness": uniqueness
|
||||||
|
})
|
||||||
|
|
||||||
if valid_candidates.size() > 0:
|
if valid_candidates.size() > 0:
|
||||||
var max_score = -1
|
var max_score = -1
|
||||||
@@ -618,7 +676,7 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
|||||||
for c in valid_candidates:
|
for c in valid_candidates:
|
||||||
if c.score == max_score: best_candidate.append(c)
|
if c.score == max_score: best_candidate.append(c)
|
||||||
|
|
||||||
var choise = best_candidate.pick_random()
|
var choise = _pick_weighted_candidate(best_candidate)
|
||||||
var new_chunk = choise.scene.instantiate()
|
var new_chunk = choise.scene.instantiate()
|
||||||
new_chunk.position = Vector3(grid_pos.x * chunk_size, 0, grid_pos.y * chunk_size)
|
new_chunk.position = Vector3(grid_pos.x * chunk_size, 0, grid_pos.y * chunk_size)
|
||||||
new_chunk.rotation.y = choise.rotation * (-PI / 2.0)
|
new_chunk.rotation.y = choise.rotation * (-PI / 2.0)
|
||||||
@@ -641,18 +699,21 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
|||||||
"heights": choise.data["heights"],
|
"heights": choise.data["heights"],
|
||||||
"node": new_chunk,
|
"node": new_chunk,
|
||||||
"info": info_new,
|
"info": info_new,
|
||||||
"have_lamppost": have_lamppost
|
"have_lamppost": have_lamppost,
|
||||||
|
"uniqueness": choise.uniqueness
|
||||||
}
|
}
|
||||||
|
|
||||||
if have_lamppost:
|
if have_lamppost:
|
||||||
_queue_lamppost_wire_connection(grid_pos)
|
_queue_lamppost_wire_connection(grid_pos)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
var backup = zone_catalogue[0].instantiate()
|
var backup_scene = _pick_backup_scene(zone_catalogue, grid_pos)
|
||||||
|
var backup = backup_scene.instantiate()
|
||||||
backup.position = Vector3(grid_pos.x * chunk_size, 0, grid_pos.y * chunk_size)
|
backup.position = Vector3(grid_pos.x * chunk_size, 0, grid_pos.y * chunk_size)
|
||||||
add_child(backup)
|
add_child(backup)
|
||||||
|
|
||||||
var info_backup = _get_cached_chunk_info(backup, zone_catalogue[0])
|
var info_backup = _get_cached_chunk_info(backup, backup_scene)
|
||||||
|
var backup_uniqueness = _get_chunk_uniqueness_from_info(info_backup)
|
||||||
|
|
||||||
var safe_heights = {
|
var safe_heights = {
|
||||||
"north": req_height_north if req_height_north != -1 else height_target,
|
"north": req_height_north if req_height_north != -1 else height_target,
|
||||||
@@ -668,7 +729,8 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
|||||||
"heights": safe_heights,
|
"heights": safe_heights,
|
||||||
"node": backup,
|
"node": backup,
|
||||||
"info": info_backup,
|
"info": info_backup,
|
||||||
"have_lamppost": false
|
"have_lamppost": false,
|
||||||
|
"uniqueness": backup_uniqueness
|
||||||
}
|
}
|
||||||
|
|
||||||
func _calculate_river_flow_direction(grid_pos: Vector2i, river_connections: Dictionary) -> Vector2:
|
func _calculate_river_flow_direction(grid_pos: Vector2i, river_connections: Dictionary) -> Vector2:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ class_name ChunkInfo
|
|||||||
|
|
||||||
@export_group("Set Piece Rules (Unique pieces)")
|
@export_group("Set Piece Rules (Unique pieces)")
|
||||||
@export var exclusive_biome: String = "" # Es: "Forest"
|
@export var exclusive_biome: String = "" # Es: "Forest"
|
||||||
|
@export_range(0, 5, 1) var uniqueness: int = 0 #0=common; 5=unique
|
||||||
|
|
||||||
@export_group("Base exit")
|
@export_group("Base exit")
|
||||||
@export var north: bool = false
|
@export var north: bool = false
|
||||||
|
|||||||
Reference in New Issue
Block a user