fix lamppost wires
This commit is contained in:
@@ -39,9 +39,12 @@ const RIVER_NEIGHBOUR_OFFSETS: Dictionary = {
|
||||
}
|
||||
|
||||
@export_group("Generation")
|
||||
@export var chunk_generation_frame_budget_usec: int = 1500 #2 ms/frame to generate chunks
|
||||
@export var chunk_cleanup_frame_budget_usec: int = 1000 #1 ms/frame per cleanup
|
||||
@export var lampost_wire_frame_budget_usec: int = 1000 #1 ms/frame per i fili dei lampioni
|
||||
#ms/frame to generate chunks
|
||||
@export var chunk_generation_frame_budget_usec: int = 1500
|
||||
#ms/frame per cleanup
|
||||
@export var chunk_cleanup_frame_budget_usec: int = 1000
|
||||
#ms/frame per i fili dei lampioni
|
||||
@export var lampost_wire_frame_budget_usec: int = 1000
|
||||
#(about 4 ms of work for frame)
|
||||
#Se compaiono chunk troppo lentamente davanti al treno:
|
||||
#aumentare generazione a 3000 o 4000
|
||||
@@ -53,32 +56,51 @@ const RIVER_NEIGHBOUR_OFFSETS: Dictionary = {
|
||||
#abbassare cleanup a 500
|
||||
|
||||
@export_group("Rails")
|
||||
@export var rail_path: Path3D #rail path
|
||||
##rail path
|
||||
@export var rail_path: Path3D
|
||||
##list of railways to choose from
|
||||
@export var railway_pool: Resource
|
||||
|
||||
@export_group("Biomes")
|
||||
@export var biome_list: Array[Biome] #list of scenes for the biome
|
||||
##list of scenes for the biome
|
||||
@export var biome_list: Array[Biome]
|
||||
|
||||
@export_group("Entities")
|
||||
##list of entities to choose from
|
||||
@export var entity_pool: Resource
|
||||
##propability of entity spawn (e.g. entity_spawn_probability 0.6 * spawn_chance 1.0 = 60%)
|
||||
@export_range(0.0, 1.0, 0.01) var entity_spawn_probability: float = 0.6
|
||||
##max spawnable entities per chunk
|
||||
@export_range(0, 20, 1) var max_entities_per_chunk: int = 3
|
||||
|
||||
@export_group("Grid and Area")
|
||||
@export var chunk_size: float = 20.0 #size of a cell; default 20 (global position is defined dividing x and z for this value)
|
||||
@export var eye_line: int = 3 #cells to be considerated around the train (e.g. 3 => a square of cells from -3 to 3 around train cell)
|
||||
@export var district_scale: float = 0.05 #noise value to distribuite biome; low values create large area, high values create biome with more variants
|
||||
##size of a cell; default 20 (global position is defined dividing x and z for this value)
|
||||
@export var chunk_size: float = 20.0
|
||||
##cells to be considerated around the train (e.g. 3 => a square of cells from -3 to 3 around train cell)
|
||||
@export var eye_line: int = 3
|
||||
##noise value to distribuite biome; low values create large area, high values create biome with more variants
|
||||
@export var district_scale: float = 0.05
|
||||
|
||||
@export_group("Lamppost")
|
||||
##lampost wire material
|
||||
@export var lamppost_wire_material: ShaderMaterial
|
||||
##lampost wire thickness
|
||||
@export_range(0.01, 1.0) var wire_thickness: float = 0.05
|
||||
@export var lamppost_dist_factor: int = 10 #max distance of connections
|
||||
##max distance of connections
|
||||
@export var lamppost_dist_factor: int = 10
|
||||
##max cells to search around a lamppost chunk
|
||||
@export_range(1, 6, 1) var lamppost_search_radius_cells: int = 3
|
||||
##max allowed distance between lamppost pairs
|
||||
@export var lamppost_max_wire_distance: float = 60.0
|
||||
##if true wire connections blocked by colliders are discarded
|
||||
@export var lamppost_obstacle_check_enabled: bool = true
|
||||
|
||||
var board: Dictionary = {}
|
||||
var last_pos_train: Vector2i = Vector2i(999999, 999999)
|
||||
var noise_generator: FastNoiseLite
|
||||
var altitude_generator: FastNoiseLite
|
||||
var wire_connections: Dictionary = {}
|
||||
var wire_connection_pairs: Dictionary = {}
|
||||
var chunk_candidate_cache: Dictionary = {} #node cache (metadata)
|
||||
var prop_candidate_cache: Dictionary = {}
|
||||
var entity_candidate_cache: Dictionary = {}
|
||||
@@ -165,6 +187,7 @@ func _destroy_and_regenrate_world() -> void:
|
||||
#Clean board and wire connections
|
||||
board.clear()
|
||||
wire_connections.clear()
|
||||
wire_connection_pairs.clear()
|
||||
|
||||
#Create train
|
||||
last_pos_train = Vector2i(999999, 999999)
|
||||
@@ -542,6 +565,18 @@ func _queue_lamppost_wire_connection(grid_pos: Vector2i) -> void:
|
||||
pending_wire_lookup[grid_pos] = true
|
||||
pending_wire_cells.append(grid_pos)
|
||||
|
||||
func _queue_lamppost_wire_connections_around(grid_pos: Vector2i) -> void:
|
||||
_queue_lamppost_wire_connection(grid_pos)
|
||||
|
||||
for x in range(-lamppost_search_radius_cells, lamppost_search_radius_cells + 1):
|
||||
for z in range(-lamppost_search_radius_cells, lamppost_search_radius_cells + 1):
|
||||
if x == 0 and z == 0:
|
||||
continue
|
||||
|
||||
var near_pos = grid_pos + Vector2i(x, z)
|
||||
if board.has(near_pos) and board[near_pos].get("have_lamppost", false):
|
||||
_queue_lamppost_wire_connection(near_pos)
|
||||
|
||||
func _drain_wire_queue() -> void:
|
||||
var processed: int = 0
|
||||
var start_usec: int = Time.get_ticks_usec()
|
||||
@@ -716,15 +751,11 @@ func _get_prop_scene_uniqueness(scene: PackedScene) -> int:
|
||||
prop_candidate_cache[key] = uniqueness
|
||||
return uniqueness
|
||||
|
||||
func _get_marker_prop_uniqueness(marker: Node) -> int:
|
||||
var uniqueness = _get_prop_uniqueness_from_info(marker)
|
||||
if uniqueness == -1:
|
||||
return 0
|
||||
return uniqueness
|
||||
|
||||
func _pick_weighted_prop_scene(marker: Node) -> PackedScene:
|
||||
var candidates = []
|
||||
var fallback_uniqueness = _get_marker_prop_uniqueness(marker)
|
||||
var fallback_uniqueness = _get_prop_uniqueness_from_info(marker)
|
||||
if fallback_uniqueness == -1:
|
||||
fallback_uniqueness = 0
|
||||
|
||||
for prop_scene in marker.available_props:
|
||||
if prop_scene == null:
|
||||
@@ -991,7 +1022,7 @@ func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
|
||||
}
|
||||
|
||||
if have_lamppost:
|
||||
_queue_lamppost_wire_connection(grid_pos)
|
||||
_queue_lamppost_wire_connections_around(grid_pos)
|
||||
|
||||
_spawn_entities_for_static_obstacle(root_chunk, grid_pos)
|
||||
|
||||
@@ -1100,7 +1131,8 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
||||
have_lamppost = info_new.have_lamppost
|
||||
|
||||
var river_flow_direction = _calculate_river_flow_direction(grid_pos, choise.data["river_connections"])
|
||||
_apply_river_flow_direction(new_chunk, river_flow_direction)
|
||||
if !river_flow_direction.is_zero_approx():
|
||||
_set_river_flow_direction_recursive(new_chunk, river_flow_direction.normalized())
|
||||
|
||||
board[grid_pos] = {
|
||||
"type": "biome",
|
||||
@@ -1115,7 +1147,7 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
||||
}
|
||||
|
||||
if have_lamppost:
|
||||
_queue_lamppost_wire_connection(grid_pos)
|
||||
_queue_lamppost_wire_connections_around(grid_pos)
|
||||
|
||||
else:
|
||||
var backup_scene = _pick_backup_scene(zone_catalogue, grid_pos)
|
||||
@@ -1231,11 +1263,6 @@ func _get_average_river_side_direction(sides: Array[String]) -> Vector2:
|
||||
return Vector2.ZERO
|
||||
return direction / float(sides.size())
|
||||
|
||||
func _apply_river_flow_direction(root: Node, flow_direction: Vector2) -> void:
|
||||
if flow_direction.is_zero_approx():
|
||||
return
|
||||
_set_river_flow_direction_recursive(root, flow_direction.normalized())
|
||||
|
||||
func _set_river_flow_direction_recursive(node: Node, flow_direction: Vector2) -> void:
|
||||
if node is MeshInstance3D and node.name.begins_with("Water_F"):
|
||||
var mesh_instance := node as MeshInstance3D
|
||||
@@ -1275,6 +1302,13 @@ func _get_lampposts(info_node: Node, side: String) -> Array[Node3D]:
|
||||
if is_instance_valid(p): lampposts.append(p)
|
||||
return lampposts
|
||||
|
||||
func _get_wire_connection_pair_key(root_a: Node, root_b: Node) -> String:
|
||||
var id_a: int = root_a.get_instance_id()
|
||||
var id_b: int = root_b.get_instance_id()
|
||||
if id_a < id_b:
|
||||
return str(id_a, ":", id_b)
|
||||
return str(id_b, ":", id_a)
|
||||
|
||||
func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
|
||||
var new_cell = board[new_board_pos]
|
||||
var new_root = new_cell["node"]
|
||||
@@ -1292,12 +1326,11 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
|
||||
|
||||
if wire_connections[new_id] >= 2: return
|
||||
|
||||
var p_sx_my_best = null; var p_dx_my_best = null
|
||||
var p_sx_your_best = null; var p_dx_your_best = null
|
||||
var best_closest_to_root = null
|
||||
var best_candidate: Dictionary = {}
|
||||
var best_distance = 999999.0
|
||||
var ray_research = 6
|
||||
|
||||
var ray_research: int = lamppost_search_radius_cells
|
||||
var max_dist: float = minf(lamppost_max_wire_distance, chunk_size * lamppost_dist_factor)
|
||||
|
||||
for x in range(-ray_research, ray_research + 1):
|
||||
for z in range(-ray_research, ray_research + 1):
|
||||
if x == 0 and z == 0: continue
|
||||
@@ -1311,9 +1344,10 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
|
||||
|
||||
var closest_id = closest_root.get_instance_id()
|
||||
var closest_connections = wire_connections.get(closest_id, 0)
|
||||
|
||||
var pair_key = _get_wire_connection_pair_key(new_root, closest_root)
|
||||
if wire_connection_pairs.has(pair_key): continue
|
||||
if closest_connections >= 2: continue
|
||||
|
||||
|
||||
if closest_info is Node3D: closest_info.force_update_transform()
|
||||
var closest_sx = _get_lampposts(closest_info, "sx")
|
||||
var closest_dx = _get_lampposts(closest_info, "dx")
|
||||
@@ -1324,32 +1358,99 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
|
||||
var my_c = (new_sx[i_m].global_position + new_dx[i_m].global_position) / 2.0
|
||||
var your_c = (closest_sx[i_t].global_position + closest_dx[i_t].global_position) / 2.0
|
||||
var dist = my_c.distance_to(your_c)
|
||||
|
||||
if dist > max_dist:
|
||||
continue
|
||||
|
||||
var p_sx_my = new_sx[i_m]
|
||||
var p_dx_my = new_dx[i_m]
|
||||
var p_sx_your = closest_sx[i_t]
|
||||
var p_dx_your = closest_dx[i_t]
|
||||
var dist_streight = p_sx_my.global_position.distance_to(p_sx_your.global_position) + p_dx_my.global_position.distance_to(p_dx_your.global_position)
|
||||
var dist_cross = p_sx_my.global_position.distance_to(p_dx_your.global_position) + p_dx_my.global_position.distance_to(p_sx_your.global_position)
|
||||
var use_cross = dist_cross < dist_streight
|
||||
|
||||
if use_cross:
|
||||
if _is_wire_path_blocked(p_sx_my.global_position, p_dx_your.global_position, [new_root, closest_root]):
|
||||
continue
|
||||
if _is_wire_path_blocked(p_dx_my.global_position, p_sx_your.global_position, [new_root, closest_root]):
|
||||
continue
|
||||
else:
|
||||
if _is_wire_path_blocked(p_sx_my.global_position, p_sx_your.global_position, [new_root, closest_root]):
|
||||
continue
|
||||
if _is_wire_path_blocked(p_dx_my.global_position, p_dx_your.global_position, [new_root, closest_root]):
|
||||
continue
|
||||
|
||||
if dist < best_distance:
|
||||
best_distance = dist
|
||||
best_closest_to_root = closest_root
|
||||
p_sx_my_best = new_sx[i_m]
|
||||
p_dx_my_best = new_dx[i_m]
|
||||
p_sx_your_best = closest_sx[i_t]
|
||||
p_dx_your_best = closest_dx[i_t]
|
||||
|
||||
var max_dist = chunk_size * lamppost_dist_factor
|
||||
|
||||
if best_closest_to_root != null and best_distance < max_dist:
|
||||
var dist_streight = p_sx_my_best.global_position.distance_to(p_sx_your_best.global_position) + p_dx_my_best.global_position.distance_to(p_dx_your_best.global_position)
|
||||
var dist_cross = p_sx_my_best.global_position.distance_to(p_dx_your_best.global_position) + p_dx_my_best.global_position.distance_to(p_sx_your_best.global_position)
|
||||
|
||||
if dist_streight <= dist_cross:
|
||||
_draw_parable(p_sx_my_best.global_position, p_sx_your_best.global_position, new_root)
|
||||
_draw_parable(p_dx_my_best.global_position, p_dx_your_best.global_position, new_root)
|
||||
best_candidate = {
|
||||
"closest_root": closest_root,
|
||||
"pair_key": pair_key,
|
||||
"p_sx_my": p_sx_my,
|
||||
"p_dx_my": p_dx_my,
|
||||
"p_sx_your": p_sx_your,
|
||||
"p_dx_your": p_dx_your,
|
||||
"use_cross": use_cross,
|
||||
}
|
||||
if not best_candidate.is_empty():
|
||||
if best_candidate["use_cross"]:
|
||||
_draw_parable(best_candidate["p_sx_my"].global_position, best_candidate["p_dx_your"].global_position, new_root)
|
||||
_draw_parable(best_candidate["p_dx_my"].global_position, best_candidate["p_sx_your"].global_position, new_root)
|
||||
else:
|
||||
_draw_parable(p_sx_my_best.global_position, p_dx_your_best.global_position, new_root)
|
||||
_draw_parable(p_dx_my_best.global_position, p_sx_your_best.global_position, new_root)
|
||||
_draw_parable(best_candidate["p_sx_my"].global_position, best_candidate["p_sx_your"].global_position, new_root)
|
||||
_draw_parable(best_candidate["p_dx_my"].global_position, best_candidate["p_dx_your"].global_position, new_root)
|
||||
|
||||
wire_connections[new_id] += 1
|
||||
var closest_id = best_closest_to_root.get_instance_id()
|
||||
wire_connection_pairs[best_candidate["pair_key"]] = true
|
||||
var closest_id = best_candidate["closest_root"].get_instance_id()
|
||||
if not wire_connections.has(closest_id): wire_connections[closest_id] = 0
|
||||
wire_connections[closest_id] += 1
|
||||
if wire_connections[new_id] < 2:
|
||||
_queue_lamppost_wire_connection(new_board_pos)
|
||||
|
||||
func _get_wire_sample_point(p1: Vector3, p2: Vector3, t: float) -> Vector3:
|
||||
var lowering: float = 1.5
|
||||
var point: Vector3 = p1.lerp(p2, t)
|
||||
var gravity: float = lowering * (1.0 - pow(2.0 * t - 1.0, 2.0))
|
||||
point.y -= gravity
|
||||
return point
|
||||
|
||||
func _collect_wire_excluded_rids(root: Node, excluded_rids: Array[RID]) -> void:
|
||||
if root == null:
|
||||
return
|
||||
|
||||
var collision_object = root as CollisionObject3D
|
||||
if collision_object != null:
|
||||
excluded_rids.append(collision_object.get_rid())
|
||||
|
||||
for child in root.get_children():
|
||||
_collect_wire_excluded_rids(child, excluded_rids)
|
||||
|
||||
func _get_wire_excluded_rids(excluded_roots: Array) -> Array[RID]:
|
||||
var excluded_rids: Array[RID] = []
|
||||
for root in excluded_roots:
|
||||
_collect_wire_excluded_rids(root, excluded_rids)
|
||||
return excluded_rids
|
||||
|
||||
func _is_wire_path_blocked(p1: Vector3, p2: Vector3, excluded_roots: Array = []) -> bool:
|
||||
if not lamppost_obstacle_check_enabled:
|
||||
return false
|
||||
|
||||
var space_state = get_world_3d().direct_space_state
|
||||
var excluded_rids: Array[RID] = _get_wire_excluded_rids(excluded_roots)
|
||||
var previous_point: Vector3 = _get_wire_sample_point(p1, p2, 0.08)
|
||||
var segments: int = 12
|
||||
for i in range(1, segments + 1):
|
||||
var t: float = lerpf(0.08, 0.92, float(i) / float(segments))
|
||||
var next_point: Vector3 = _get_wire_sample_point(p1, p2, t)
|
||||
var query = PhysicsRayQueryParameters3D.create(previous_point, next_point)
|
||||
query.exclude = excluded_rids
|
||||
query.collide_with_areas = true
|
||||
var result = space_state.intersect_ray(query)
|
||||
if not result.is_empty():
|
||||
return true
|
||||
previous_point = next_point
|
||||
|
||||
return false
|
||||
|
||||
#draw lamppost wires
|
||||
func _draw_parable(p1: Vector3, p2: Vector3, parent: Node3D) -> void:
|
||||
|
||||
@@ -200,7 +200,7 @@ compositor = SubResource("Compositor_mb5yv")
|
||||
rail_path = NodePath("../rail")
|
||||
biome_list = Array[ExtResource("6_jfe74")]([SubResource("Resource_3qrd0")])
|
||||
entity_pool = ExtResource("34_a2cst")
|
||||
entity_spawn_probability = 1.0
|
||||
entity_spawn_probability = 0.7
|
||||
eye_line = 4
|
||||
|
||||
[node name="Terrain" type="MeshInstance3D" parent="." unique_id=219178561]
|
||||
|
||||
Reference in New Issue
Block a user