Merge branch 'main' into improve-ui
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
|
||||
[node name="AiCow" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_p2hpa")]
|
||||
anim_player = NodePath("CowMannequin/AnimationPlayer")
|
||||
entity_type = 1
|
||||
entity_name = "Cow"
|
||||
|
||||
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||
initial_state = NodePath("IdleState")
|
||||
|
||||
@@ -15,6 +15,8 @@ _data = {
|
||||
|
||||
[node name="AiHorse" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_e5v3h")]
|
||||
anim_player = NodePath("HorseMannequin/AnimationPlayer")
|
||||
entity_type = 1
|
||||
entity_name = "Horse"
|
||||
|
||||
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||
initial_state = NodePath("IdleState")
|
||||
@@ -35,7 +37,7 @@ exit_on_action_finished = true
|
||||
[node name="HorseMannequin" parent="." index="3" unique_id=1289880358 instance=ExtResource("2_4t6jw")]
|
||||
transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, -0.9, 0)
|
||||
|
||||
[node name="Skeleton3D" parent="HorseMannequin/Armature" parent_id_path=PackedInt32Array(1289880358, 245823720) index="0" unique_id=494955820]
|
||||
[node name="Skeleton3D" parent="HorseMannequin/Armature" parent_id_path=PackedInt32Array(1289880358, 1841497289) index="0" unique_id=1502661928]
|
||||
bones/1/rotation = Quaternion(0.7071068, -6.209646e-07, -6.209645e-07, 0.7071067)
|
||||
bones/4/rotation = Quaternion(0.0012952884, -0.0012955684, 0.7071056, 0.7071057)
|
||||
bones/5/rotation = Quaternion(0.70685357, -0.70227593, -0.04508998, 0.07164877)
|
||||
@@ -63,7 +65,7 @@ bones/33/rotation = Quaternion(0.7071068, -6.209646e-07, -6.209645e-07, 0.707106
|
||||
bones/35/rotation = Quaternion(0.7071068, -9.581396e-07, -9.581394e-07, 0.7071067)
|
||||
bones/37/rotation = Quaternion(0.7071068, -9.581396e-07, -9.581394e-07, 0.7071067)
|
||||
|
||||
[node name="AnimationPlayer" parent="HorseMannequin" index="1" unique_id=272680130]
|
||||
[node name="AnimationPlayer" parent="HorseMannequin" index="1" unique_id=1876493257]
|
||||
libraries/custom = SubResource("AnimationLibrary_or6xs")
|
||||
|
||||
[editable path="HorseMannequin"]
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
[ext_resource type="PackedScene" uid="uid://mvh2v6v72stt" path="res://core/ai/agents/human/ai_human.tscn" id="1_awhwq"]
|
||||
|
||||
[node name="AiCitizen" unique_id=1228675528 instance=ExtResource("1_awhwq")]
|
||||
|
||||
[node name="StateMachine" parent="." index="3" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||
initial_state = NodePath("")
|
||||
entity_name = "Citizen"
|
||||
|
||||
[editable path="HumanMannequin"]
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
[ext_resource type="PackedScene" uid="uid://bdqeshcwwnyc4" path="res://core/ai/agents/human/ai_citizen.tscn" id="1_cduuu"]
|
||||
|
||||
[node name="AiCitizenSitter" unique_id=1228675528 instance=ExtResource("1_cduuu")]
|
||||
entity_name = "CitizenSitter"
|
||||
|
||||
[node name="SK_Mannequin" parent="HumanMannequin" parent_id_path=PackedInt32Array(333236377) index="0" unique_id=377304892]
|
||||
[node name="SK_Mannequin" parent="HumanMannequin" parent_id_path=PackedInt32Array(333236377) index="0" unique_id=1085647626]
|
||||
transform = Transform3D(0.99906886, 0.025971904, -0.03444738, 0.038254507, -0.16420224, 0.98568463, 0.019943757, -0.98608464, -0.1650429, 0.034450583, -0.44864154, 0.18535595)
|
||||
|
||||
[node name="Skeleton3D" parent="HumanMannequin/SK_Mannequin" index="0" unique_id=427572412]
|
||||
[node name="Skeleton3D" parent="HumanMannequin/SK_Mannequin" index="0" unique_id=1674820390]
|
||||
bones/2/rotation = Quaternion(-0.007029906, 0.032859802, -0.23654123, 0.97104025)
|
||||
bones/3/rotation = Quaternion(-0.000884556, 0.0033522977, 0.10280211, 0.99469584)
|
||||
bones/4/rotation = Quaternion(-0.00040807336, 0.0034836144, 0.0045103733, 0.9999837)
|
||||
@@ -47,7 +48,7 @@ bones/55/rotation = Quaternion(0.0132777635, 0.10731075, 0.71409845, -0.6916441)
|
||||
bones/56/rotation = Quaternion(0.03920827, -0.09832406, -0.75485575, 0.64729285)
|
||||
bones/58/rotation = Quaternion(0.01656407, -0.06386153, 0.030505493, 0.9973549)
|
||||
|
||||
[node name="AnimationPlayer" parent="HumanMannequin" parent_id_path=PackedInt32Array(333236377) index="1" unique_id=233699491]
|
||||
[node name="AnimationPlayer" parent="HumanMannequin" parent_id_path=PackedInt32Array(333236377) index="1" unique_id=1460197763]
|
||||
autoplay = &"custom/sit"
|
||||
|
||||
[editable path="HumanMannequin"]
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
[ext_resource type="Script" uid="uid://bngfthvt04ivv" path="res://core/ai/framework/patrol_state.gd" id="3_8d0tj"]
|
||||
|
||||
[node name="AiCitizenWalker" unique_id=1228675528 instance=ExtResource("1_dms8s")]
|
||||
entity_name = "CitizenWalker"
|
||||
|
||||
[node name="StateMachine" parent="." index="3" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||
initial_state = NodePath("IdleState")
|
||||
|
||||
[node name="IdleState" type="Node" parent="StateMachine" index="0" unique_id=42226979]
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
[ext_resource type="Script" uid="uid://d3hy70ec8vqo5" path="res://core/ai/framework/run_animation_state.gd" id="4_2oda6"]
|
||||
|
||||
[node name="AiFarmer" unique_id=1228675528 instance=ExtResource("1_l2y7m")]
|
||||
entity_name = "Farmer"
|
||||
allowed_biomes = Array[String](["countryside"])
|
||||
|
||||
[node name="StateMachine" parent="." index="3" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||
initial_state = NodePath("GatherState")
|
||||
|
||||
[node name="PatrolState" type="Node" parent="StateMachine" index="0" unique_id=930272128]
|
||||
|
||||
@@ -15,6 +15,8 @@ _data = {
|
||||
|
||||
[node name="AiPig" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_j8spt")]
|
||||
anim_player = NodePath("PigMannequin/AnimationPlayer")
|
||||
entity_type = 1
|
||||
entity_name = "Pig"
|
||||
|
||||
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||
initial_state = NodePath("IdleState")
|
||||
@@ -35,7 +37,7 @@ exit_on_action_finished = true
|
||||
[node name="PigMannequin" parent="." index="3" unique_id=926755470 instance=ExtResource("2_qmc2e")]
|
||||
transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, -0.9, 0)
|
||||
|
||||
[node name="Skeleton3D" parent="PigMannequin/Armature" parent_id_path=PackedInt32Array(926755470, 695496535) index="0" unique_id=725647261]
|
||||
[node name="Skeleton3D" parent="PigMannequin/Armature" parent_id_path=PackedInt32Array(926755470, 2144155651) index="0" unique_id=1681287116]
|
||||
bones/1/rotation = Quaternion(0.7071068, -7.052583e-07, -7.052583e-07, 0.7071067)
|
||||
bones/3/position = Vector3(5.37765e-05, 0.017809996, -0.007695386)
|
||||
bones/3/rotation = Quaternion(-0.027121998, 0, 0, 0.99963224)
|
||||
@@ -70,7 +72,7 @@ bones/31/rotation = Quaternion(0.7071068, -1.0424332e-06, -1.0424329e-06, 0.7071
|
||||
bones/33/position = Vector3(0.010670463, 0.0010000349, -0.03166372)
|
||||
bones/33/rotation = Quaternion(0.70755845, -7.1388774e-07, -1.0355643e-06, 0.7066547)
|
||||
|
||||
[node name="AnimationPlayer" parent="PigMannequin" index="1" unique_id=904091745]
|
||||
[node name="AnimationPlayer" parent="PigMannequin" index="1" unique_id=1489956231]
|
||||
libraries/custom = SubResource("AnimationLibrary_lvpc5")
|
||||
|
||||
[editable path="PigMannequin"]
|
||||
|
||||
@@ -15,6 +15,8 @@ _data = {
|
||||
|
||||
[node name="AiPug" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_0bu1i")]
|
||||
anim_player = NodePath("PugMannequin/AnimationPlayer")
|
||||
entity_type = 1
|
||||
entity_name = "Pug"
|
||||
|
||||
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||
initial_state = NodePath("IdleState")
|
||||
@@ -35,7 +37,7 @@ exit_on_action_finished = true
|
||||
[node name="PugMannequin" parent="." index="3" unique_id=1732134047 instance=ExtResource("2_n0mit")]
|
||||
transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, -0.9, 0)
|
||||
|
||||
[node name="Skeleton3D" parent="PugMannequin/Armature" parent_id_path=PackedInt32Array(1732134047, 199608791) index="0" unique_id=33809722]
|
||||
[node name="Skeleton3D" parent="PugMannequin/Armature" parent_id_path=PackedInt32Array(1732134047, 413342048) index="0" unique_id=1846443987]
|
||||
bones/8/position = Vector3(-0.0054483665, 0.008346455, -0.020266803)
|
||||
bones/8/rotation = Quaternion(-0.007561639, 0.007561228, 0.70706636, 0.70706636)
|
||||
bones/9/rotation = Quaternion(0.6665347, -0.6790185, 0.20055033, -0.23333457)
|
||||
@@ -49,7 +51,7 @@ bones/20/rotation = Quaternion(0.6013276, -0.007656022, 0.017799761, 0.79876757)
|
||||
bones/24/rotation = Quaternion(-0.45064288, -0.22904137, 0.090387635, 0.858074)
|
||||
bones/27/rotation = Quaternion(0.05229574, 5.703821e-05, -0.025155801, 0.99831474)
|
||||
|
||||
[node name="AnimationPlayer" parent="PugMannequin" index="1" unique_id=1653203922]
|
||||
[node name="AnimationPlayer" parent="PugMannequin" index="1" unique_id=1265653636]
|
||||
libraries/custom = SubResource("AnimationLibrary_iapui")
|
||||
|
||||
[editable path="PugMannequin"]
|
||||
|
||||
@@ -15,6 +15,8 @@ _data = {
|
||||
|
||||
[node name="AiSheep" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_smbiq")]
|
||||
anim_player = NodePath("SheepMannequin/AnimationPlayer")
|
||||
entity_type = 1
|
||||
entity_name = "Sheep"
|
||||
|
||||
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||
initial_state = NodePath("IdleState")
|
||||
@@ -35,10 +37,10 @@ exit_on_action_finished = true
|
||||
[node name="SheepMannequin" parent="." index="3" unique_id=1153770042 instance=ExtResource("2_hnenk")]
|
||||
transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, -0.9, 0)
|
||||
|
||||
[node name="Armature" parent="SheepMannequin" index="0" unique_id=62421163]
|
||||
[node name="Armature" parent="SheepMannequin" index="0" unique_id=1455361254]
|
||||
transform = Transform3D(100, 0, 0, 0, -4.3711384e-06, 99.99999, 0, -99.99999, -4.3711384e-06, 0, 0, 0)
|
||||
|
||||
[node name="AnimationPlayer" parent="SheepMannequin" index="1" unique_id=676833932]
|
||||
[node name="AnimationPlayer" parent="SheepMannequin" index="1" unique_id=2025108985]
|
||||
libraries/custom = SubResource("AnimationLibrary_vlyix")
|
||||
|
||||
[editable path="SheepMannequin"]
|
||||
|
||||
@@ -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,35 +56,55 @@ 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 = {}
|
||||
var static_entity_spawn_roots: Dictionary = {}
|
||||
var pending_generation_cells: Array[Vector2i] = []
|
||||
var pending_cleanup_cells: Array[Vector2i] = []
|
||||
var pending_wire_cells: Array[Vector2i] = []
|
||||
@@ -116,6 +139,7 @@ func _ready() -> void:
|
||||
_warm_rail_chunk_catalogue()
|
||||
#set unique pieces
|
||||
_update_set_pieces()
|
||||
_spawn_entities_for_static_spawn_points()
|
||||
|
||||
func _update_set_pieces() -> void:
|
||||
var set_pieces = get_tree().get_nodes_in_group("set_pieces")
|
||||
@@ -163,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)
|
||||
@@ -540,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()
|
||||
@@ -714,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:
|
||||
@@ -766,6 +799,71 @@ func _spawn_prop_for_marker(marker: Node) -> void:
|
||||
marker.add_child(prop_node)
|
||||
prop_node.transform = Transform3D.IDENTITY
|
||||
|
||||
func _get_static_entity_spawn_root(root: Node) -> Node:
|
||||
var current: Node = root
|
||||
|
||||
while current != null and current != get_tree().root:
|
||||
var spawn_points: Array[Node] = []
|
||||
collect_all_entity_spawn_points(current, spawn_points)
|
||||
if not spawn_points.is_empty():
|
||||
return current
|
||||
current = current.get_parent()
|
||||
|
||||
return null
|
||||
|
||||
func _get_static_spawn_chunk_root_from_point(spawn_point: Node) -> Node:
|
||||
var current: Node = spawn_point
|
||||
|
||||
while current != null and current != get_tree().root:
|
||||
var info_list: Array[Node] = []
|
||||
collect_all_chunkinfo(current, info_list)
|
||||
if not info_list.is_empty():
|
||||
return current
|
||||
current = current.get_parent()
|
||||
|
||||
return null
|
||||
|
||||
func _get_static_entity_spawn_key(spawn_root: Node) -> String:
|
||||
if spawn_root.scene_file_path != "":
|
||||
return spawn_root.scene_file_path
|
||||
return "instance:%s" % spawn_root.get_instance_id()
|
||||
|
||||
func _spawn_entities_for_static_spawn_points() -> void:
|
||||
var current_scene = get_tree().current_scene
|
||||
if current_scene == null:
|
||||
return
|
||||
|
||||
var spawn_points: Array[Node] = []
|
||||
collect_all_entity_spawn_points(current_scene, spawn_points)
|
||||
for spawn_point in spawn_points:
|
||||
var spawn_root = _get_static_spawn_chunk_root_from_point(spawn_point)
|
||||
if spawn_root == null:
|
||||
continue
|
||||
|
||||
var point_node = spawn_point as Node3D
|
||||
var grid_pos = Vector2i.ZERO
|
||||
if point_node != null:
|
||||
grid_pos = Vector2i(roundi(point_node.global_position.x / chunk_size), roundi(point_node.global_position.z / chunk_size))
|
||||
_spawn_entities_for_static_obstacle(spawn_root, grid_pos)
|
||||
|
||||
func _spawn_entities_for_static_obstacle(root: Node, grid_pos: Vector2i) -> void:
|
||||
if root == null or not is_instance_valid(root):
|
||||
return
|
||||
|
||||
var spawn_root = _get_static_entity_spawn_root(root)
|
||||
if spawn_root == null or not is_instance_valid(spawn_root):
|
||||
return
|
||||
|
||||
var root_key: String = _get_static_entity_spawn_key(spawn_root)
|
||||
if static_entity_spawn_roots.has(root_key):
|
||||
var tracked_root = static_entity_spawn_roots[root_key]
|
||||
if is_instance_valid(tracked_root):
|
||||
return
|
||||
static_entity_spawn_roots.erase(root_key)
|
||||
|
||||
static_entity_spawn_roots[root_key] = spawn_root
|
||||
_spawn_entities_for_chunk(spawn_root, _choose_biome_name_by_cell(grid_pos))
|
||||
|
||||
func _spawn_entities_for_chunk(root: Node, biome_name: String) -> void:
|
||||
if entity_pool == null or not "available_entities" in entity_pool:
|
||||
return
|
||||
@@ -929,7 +1027,9 @@ 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)
|
||||
|
||||
return true
|
||||
return false
|
||||
@@ -1036,7 +1136,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",
|
||||
@@ -1051,7 +1152,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)
|
||||
@@ -1167,11 +1268,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
|
||||
@@ -1211,6 +1307,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"]
|
||||
@@ -1228,12 +1331,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
|
||||
@@ -1247,9 +1349,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")
|
||||
@@ -1260,32 +1363,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:
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
[gd_resource type="Resource" script_class="EntityPool" format=3 uid="uid://cmd6s6thq4f7r"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://clx701xdwelgx" path="res://core/ai/agents/base/ai_base.tscn" id="1_0kfj8"]
|
||||
[ext_resource type="PackedScene" uid="uid://dd8wn62anbts8" path="res://core/ai/agents/cow/ai_cow.tscn" id="1_iqga3"]
|
||||
[ext_resource type="Script" uid="uid://53ryr0fsqiq7" path="res://core/biome_generator/entity_pool.gd" id="1_vccp2"]
|
||||
[ext_resource type="PackedScene" uid="uid://c2hg6hu2y5srb" path="res://core/ai/agents/pig/ai_pig.tscn" id="2_76rvd"]
|
||||
[ext_resource type="PackedScene" uid="uid://2md4l83fy8kr" path="res://core/ai/agents/pug/ai_pug.tscn" id="3_hq17p"]
|
||||
[ext_resource type="PackedScene" uid="uid://cayakdk7gmlyg" path="res://core/ai/agents/horse/ai_horse.tscn" id="4_5yjl1"]
|
||||
[ext_resource type="PackedScene" uid="uid://mvh2v6v72stt" path="res://core/ai/agents/human/ai_human.tscn" id="5_xd1cg"]
|
||||
[ext_resource type="PackedScene" uid="uid://bs1bdtm7jdtgb" path="res://core/ai/agents/sheep/ai_sheep.tscn" id="6_ql0wl"]
|
||||
[ext_resource type="PackedScene" uid="uid://ceqxsqfiotm5j" path="res://core/ai/agents/human/ai_farmer.tscn" id="7_hhs8l"]
|
||||
[ext_resource type="PackedScene" uid="uid://bdqeshcwwnyc4" path="res://core/ai/agents/human/ai_citizen.tscn" id="8_8l6th"]
|
||||
[ext_resource type="PackedScene" uid="uid://bbseno7clbepx" path="res://core/ai/agents/human/ai_citizen_sitter.tscn" id="9_x3pn3"]
|
||||
[ext_resource type="PackedScene" uid="uid://bnnuke5e7e1yr" path="res://core/ai/agents/human/ai_citizen_walker.tscn" id="10_ctysb"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_vccp2")
|
||||
name = "Entity Pool"
|
||||
available_entities = Array[PackedScene]([ExtResource("1_0kfj8")])
|
||||
available_entities = Array[PackedScene]([ExtResource("1_iqga3"), ExtResource("2_76rvd"), ExtResource("3_hq17p"), ExtResource("4_5yjl1"), ExtResource("5_xd1cg"), ExtResource("6_ql0wl"), ExtResource("7_hhs8l"), ExtResource("8_8l6th"), ExtResource("9_x3pn3"), ExtResource("10_ctysb")])
|
||||
|
||||
@@ -538,10 +538,6 @@ func _snap_wagons_to_progress(total_length: float = 0.0) -> void:
|
||||
if total_length <= 0.0:
|
||||
return
|
||||
|
||||
var direction: float = 1.0
|
||||
if train_speed < 0.0:
|
||||
direction = -1.0
|
||||
|
||||
for i in range(wagon_instances.size()):
|
||||
var wagon: Node3D = wagon_instances[i]
|
||||
if not is_instance_valid(wagon):
|
||||
@@ -551,7 +547,7 @@ func _snap_wagons_to_progress(total_length: float = 0.0) -> void:
|
||||
if i < wagon_progress_offsets.size():
|
||||
wagon_offset = wagon_progress_offsets[i]
|
||||
|
||||
var wagon_progress: float = train_progress - direction * wagon_offset
|
||||
var wagon_progress: float = train_progress - wagon_offset
|
||||
|
||||
var vehicle_progress: float = wrapf(wagon_progress, 0.0, total_length)
|
||||
var center_position: Vector3 = to_global(curve.sample_baked(vehicle_progress, true))
|
||||
|
||||
@@ -10,9 +10,8 @@
|
||||
[ext_resource type="PackedScene" uid="uid://fi6faw7ag1i0" path="res://tgcc/chunk/railway/scene/chunk_railway_curve_3.tscn" id="8_r0882"]
|
||||
[ext_resource type="PackedScene" uid="uid://dglpoh63x2lpy" path="res://tgcc/chunk/railway/scene/chunk_railway_curve_4.tscn" id="9_3auto"]
|
||||
[ext_resource type="Script" uid="uid://c374rv220mvh1" path="res://core/biome_generator/railway_pool.gd" id="9_8tdc7"]
|
||||
[ext_resource type="PackedScene" uid="uid://bup6gwlxos0w2" path="res://tgcc/chunk/railway/hero/chunk_railway_station_hero.tscn" id="10_3auto"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("9_8tdc7")
|
||||
name = "Railway Pool"
|
||||
available_railways = Array[PackedScene]([ExtResource("1_86h1y"), ExtResource("3_3auto"), ExtResource("4_i1umq"), ExtResource("5_x44at"), ExtResource("6_vrrkw"), ExtResource("7_l17bw"), ExtResource("8_qcl5o"), ExtResource("8_r0882"), ExtResource("9_3auto"), ExtResource("10_3auto")])
|
||||
available_railways = Array[PackedScene]([ExtResource("1_86h1y"), ExtResource("3_3auto"), ExtResource("4_i1umq"), ExtResource("5_x44at"), ExtResource("6_vrrkw"), ExtResource("7_l17bw"), ExtResource("8_qcl5o"), ExtResource("8_r0882"), ExtResource("9_3auto")])
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
class_name EdgeDetectionCompositor
|
||||
extends CompositorEffect
|
||||
|
||||
# --- MODIFICATO: Parametro esportato per l'Inspector ---
|
||||
@export_range(0.0, 5.0, 0.1) var line_thickness: float = 1.0
|
||||
|
||||
var rd: RenderingDevice
|
||||
var shader: RID
|
||||
var pipeline: RID
|
||||
@@ -78,8 +81,8 @@ func _render_callback(p_effect_callback_type: EffectCallbackType, p_render_data:
|
||||
var texture_sampler = RDSamplerState.new()
|
||||
texture_sampler = rd.sampler_create(texture_sampler)
|
||||
|
||||
|
||||
var parameters := PackedFloat32Array([size.x, size.y, 0.0, 0.0])
|
||||
# --- MODIFICATO: Inviato il parametro line_thickness nel buffer GPU ---
|
||||
var parameters := PackedFloat32Array([size.x, size.y, line_thickness, 0.0])
|
||||
var inv_proj_mat := p_render_data.get_render_scene_data().get_cam_projection().inverse()
|
||||
var inv_proj_mat_array := PackedVector4Array([inv_proj_mat.x, inv_proj_mat.y, inv_proj_mat.z, inv_proj_mat.w])
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
|
||||
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
|
||||
// --- MODIFICATO: Inserito line_thickness e mantenuto il padding (reserved) ---
|
||||
layout(set = 0, binding = 0, std430) readonly buffer Params {
|
||||
vec2 raster_size;
|
||||
vec2 reserved;
|
||||
float line_thickness;
|
||||
float reserved;
|
||||
mat4 inv_proj_mat;
|
||||
} params;
|
||||
|
||||
@@ -89,12 +91,13 @@ void main() {
|
||||
|
||||
// Da qui in poi, il codice prosegue normalmente solo per gli altri oggetti
|
||||
|
||||
// UV ofssets
|
||||
// --- MODIFICATO: Aggiunto multiplier "thickness" agli UV offsets ---
|
||||
float thickness = params.line_thickness;
|
||||
vec2 uv_offsets[4];
|
||||
uv_offsets[0] = uv_normalized + vec2(0.0, -1.0) * texel_size + offset;
|
||||
uv_offsets[1] = uv_normalized + vec2(0.0, 1.0) * texel_size + offset;
|
||||
uv_offsets[2] = uv_normalized + vec2(1.0, 0.0) * texel_size + offset;
|
||||
uv_offsets[3] = uv_normalized + vec2(-1.0, 0.0) * texel_size + offset;
|
||||
uv_offsets[0] = uv_normalized + vec2(0.0, -1.0) * texel_size * thickness + offset;
|
||||
uv_offsets[1] = uv_normalized + vec2(0.0, 1.0) * texel_size * thickness + offset;
|
||||
uv_offsets[2] = uv_normalized + vec2(1.0, 0.0) * texel_size * thickness + offset;
|
||||
uv_offsets[3] = uv_normalized + vec2(-1.0, 0.0) * texel_size * thickness + offset;
|
||||
|
||||
float mask = ceil(raw_roughness);
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ void fragment() {
|
||||
} else {
|
||||
vec2 projected_xz = world_pos.xz + (world_pos.y * sun_angle);
|
||||
vec2 uv = projected_xz * cloud_scale;
|
||||
uv += TIME * cloud_speed * direction;
|
||||
uv -= TIME * cloud_speed * direction;
|
||||
|
||||
float n = texture(noise_texture, uv).r;
|
||||
|
||||
@@ -71,4 +71,4 @@ void fragment() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ void sky() {
|
||||
|
||||
//Clouds
|
||||
vec2 cloud_uv = EYEDIR.xz / (EYEDIR.y + 0.5);
|
||||
cloud_uv = cloud_uv * cloud_scale + (TIME * cloud_direction * cloud_speed);
|
||||
cloud_uv = cloud_uv * cloud_scale - (TIME * cloud_direction * cloud_speed);
|
||||
float noise = texture(cloud_noise, cloud_uv).r;
|
||||
float cloud_alpha = smoothstep(cloud_threshold, cloud_threshold + cloud_edge_softness, noise);
|
||||
float color_gradient = smoothstep(cloud_threshold, cloud_threshold + cloud_edge_thickness, noise);
|
||||
@@ -136,4 +136,4 @@ void sky() {
|
||||
final_sky = mix(final_sky, current_cloud_color, cloud_alpha);
|
||||
|
||||
COLOR = final_sky;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
class_name WeatherController
|
||||
extends Node
|
||||
|
||||
signal wind_parameters_changed(speed: float, strength: float, fade: float, direction: Vector2)
|
||||
|
||||
var thunder_audio_player: AudioStreamPlayer
|
||||
var thunder_sounds: Array[AudioStream]
|
||||
var rain_sounds: Array[AudioStream]
|
||||
@@ -101,6 +103,8 @@ func _init(wind: GPUParticles3D, snow: GPUParticles3D,
|
||||
camera_pivot.get_node("pivot").camera_changed.connect(_set_camera)
|
||||
|
||||
func _ready() -> void:
|
||||
#used for wind change state (wind_decoration)
|
||||
add_to_group("weather_controller")
|
||||
|
||||
#connect events
|
||||
UIEvents.toggle_rain.connect(toggle_rain)
|
||||
@@ -439,7 +443,7 @@ func _apply_wind_config() -> void:
|
||||
else:
|
||||
wind_cross = wind_cross.normalized()
|
||||
var wind_up := wind_cross.cross(wind_axis).normalized()
|
||||
proc_mat_wind.direction = wind_axis
|
||||
proc_mat_wind.direction = Vector3.UP
|
||||
particles_wind.global_transform = Transform3D(Basis(wind_cross, wind_axis, wind_up), particles_wind.global_position)
|
||||
|
||||
_apply_wind_state(true)
|
||||
@@ -469,14 +473,23 @@ func _apply_wind_state(immediate: bool = false) -> void:
|
||||
func _set_current_wind_speed(value: float) -> void:
|
||||
current_wind_speed = value
|
||||
RenderingServer.global_shader_parameter_set("global_wind_speed", value)
|
||||
_sync_wind_event_state()
|
||||
|
||||
func _set_current_wind_strength(value: float) -> void:
|
||||
current_wind_strength = value
|
||||
RenderingServer.global_shader_parameter_set("global_wind_strength", value)
|
||||
_sync_wind_event_state()
|
||||
|
||||
func _set_current_wind_fade(value: float) -> void:
|
||||
current_wind_fade = value
|
||||
RenderingServer.global_shader_parameter_set("global_wind_fade", value)
|
||||
_sync_wind_event_state()
|
||||
|
||||
func _sync_wind_event_state() -> void:
|
||||
if environment_config == null:
|
||||
return
|
||||
#used to notify wind_decoration when wind change state
|
||||
wind_parameters_changed.emit(current_wind_speed, current_wind_strength, current_wind_fade, environment_config.wind_direction)
|
||||
|
||||
func _finish_wind_fade_out() -> void:
|
||||
if is_windy:
|
||||
|
||||
Reference in New Issue
Block a user