fix terrain collision and water recovery

This commit is contained in:
Alexander Sellite 2026-08-25 00:12:01 -04:00
parent da7f072365
commit 1ab2a291d2
13 changed files with 110 additions and 11 deletions

View file

@ -453,6 +453,7 @@ func _configure_fresh_water(records: Array[Dictionary]) -> void:
PlayerWaterTrigger.EntryHeightReference.PLAYER_ORIGIN
)
body.recovery_entry_depth_threshold = 0.1
body.recovery_entry_confirmation_seconds = 0.2
body.fish_pool = _fresh_water_pool(tags)
body.location_tags = _fresh_water_location_tags(tags)
body.selection_priority = 10

View file

@ -11,7 +11,7 @@ packed_scene = ExtResource("2_scene")
procedural_group = &"sand_tree"
required_chunk_tags = PackedStringArray("sand")
minimum_spawn_chunk_distance = 2
clearance_radius = 0.65
clearance_radius = 0.75
minimum_visual_scale = 0.5
maximum_visual_scale = 1.0
minimum_cluster_size = 2
@ -21,6 +21,7 @@ maximum_cluster_radius = 3.0
prefer_ocean_facing = true
local_overhang_direction = Vector2(-0.883, 0.469)
ocean_facing_spread_degrees = 55.0
collision_radius = 0.4
collision_radius = 0.7
collision_height = 6.0
collision_offset = Vector3(0.15, 0, -0.1)
gatherable_surface_material_names = PackedStringArray("wood_light")

View file

@ -15,5 +15,6 @@ minimum_spawn_chunk_distance = 2
clearance_radius = 1.55
minimum_visual_scale = 0.65
maximum_visual_scale = 1.2
collision_radius = 0.5
collision_radius = 0.85
collision_height = 4.0
collision_offset = Vector3(-0.044, 0, 0.083)

View file

@ -15,5 +15,6 @@ minimum_spawn_chunk_distance = 2
clearance_radius = 1.65
minimum_visual_scale = 0.75
maximum_visual_scale = 1.2
collision_radius = 0.65
collision_radius = 0.75
collision_height = 9.5
collision_offset = Vector3(-0.04, 0, 0.075)

View file

@ -27,4 +27,5 @@ secondary_variant_material_slot_names = PackedStringArray("wood", "wood_light",
secondary_material_variants = Array[Material]([ExtResource("6_wood_light"), ExtResource("7_wood_mid"), ExtResource("8_wood_dark")])
collision_radius = 0.4
collision_height = 3.2
collision_offset = Vector3(0.08, 0, 0.01)
gatherable_surface_material_names = PackedStringArray("wood", "wood_light", "wood_mid", "wood_dark")

View file

@ -25,6 +25,7 @@ variant_material_slot_names = PackedStringArray("leaf_light", "leaf", "leaf_dark
material_variants = Array[Material]([ExtResource("3_leaf_light"), ExtResource("4_leaf_mid"), ExtResource("5_leaf_dark")])
secondary_variant_material_slot_names = PackedStringArray("wood", "wood_light", "wood_mid")
secondary_material_variants = Array[Material]([ExtResource("6_wood_light"), ExtResource("7_wood_mid"), ExtResource("8_wood_dark")])
collision_radius = 0.5
collision_radius = 0.55
collision_height = 3.8
collision_offset = Vector3(0.1, 0, 0.075)
gatherable_surface_material_names = PackedStringArray("wood", "wood_light", "wood_mid", "wood_dark")

View file

@ -27,4 +27,5 @@ secondary_variant_material_slot_names = PackedStringArray("wood", "wood_light",
secondary_material_variants = Array[Material]([ExtResource("6_wood_light"), ExtResource("7_wood_mid"), ExtResource("8_wood_dark")])
collision_radius = 0.55
collision_height = 4.2
collision_offset = Vector3(-0.1, 0, 0.18)
gatherable_surface_material_names = PackedStringArray("wood", "wood_light", "wood_mid", "wood_dark")

View file

@ -25,6 +25,7 @@ variant_material_slot_names = PackedStringArray("leaf_light", "leaf", "leaf_dark
material_variants = Array[Material]([ExtResource("3_leaf_light"), ExtResource("4_leaf_mid"), ExtResource("5_leaf_dark")])
secondary_variant_material_slot_names = PackedStringArray("wood", "wood_light", "wood_mid")
secondary_material_variants = Array[Material]([ExtResource("6_wood_light"), ExtResource("7_wood_mid"), ExtResource("8_wood_dark")])
collision_radius = 0.85
collision_radius = 1.05
collision_height = 7.5
collision_offset = Vector3(0.084, 0, 0.504)
gatherable_surface_material_names = PackedStringArray("wood", "wood_light", "wood_mid", "wood_dark")

View file

@ -29,9 +29,14 @@ enum EntryHeightReference {
)
## Recovery begins when the selected reference reaches this depth.
@export_range(0.0, 2.0, 0.05) var entry_depth_threshold: float = 0.35
## The player must remain below the threshold for this long before recovery.
## A short freshwater confirmation keeps jumps across stepping stones from
## being mistaken for a completed fall into the water.
@export_range(0.0, 1.0, 0.05) var entry_confirmation_seconds: float = 0.0
var _tracked_players: Array[Player] = []
var _triggered_players: Dictionary[StringName, bool] = {}
var _submerged_seconds: Dictionary[StringName, float] = {}
func _ready() -> void:
@ -46,7 +51,7 @@ func _ready() -> void:
set_physics_process(false)
func _physics_process(_delta: float) -> void:
func _physics_process(delta: float) -> void:
var active_surface_height: float = get_surface_height()
for player: Player in _tracked_players.duplicate():
if not is_instance_valid(player):
@ -58,9 +63,17 @@ func _physics_process(_delta: float) -> void:
var entry_height := player.get_body_center_position().y
if entry_height_reference == EntryHeightReference.PLAYER_ORIGIN:
entry_height = player.global_position.y
if entry_height <= active_surface_height - entry_depth_threshold:
_triggered_players[player_key] = true
recovery_requested.emit(player, active_surface_height)
if entry_height > active_surface_height - entry_depth_threshold:
_submerged_seconds[player_key] = 0.0
continue
var submerged_seconds: float = (
_submerged_seconds.get(player_key, 0.0) + maxf(delta, 0.0)
)
_submerged_seconds[player_key] = submerged_seconds
if submerged_seconds < entry_confirmation_seconds:
continue
_triggered_players[player_key] = true
recovery_requested.emit(player, active_surface_height)
if _tracked_players.is_empty():
set_physics_process(false)
@ -86,6 +99,7 @@ func _on_body_entered(body: Node3D) -> void:
if player == null or player in _tracked_players:
return
_tracked_players.append(player)
_submerged_seconds[StringName(str(player.get_instance_id()))] = 0.0
set_physics_process(true)
@ -94,6 +108,8 @@ func _on_body_exited(body: Node3D) -> void:
if player == null:
return
_tracked_players.erase(player)
_triggered_players.erase(StringName(str(player.get_instance_id())))
var player_key := StringName(str(player.get_instance_id()))
_triggered_players.erase(player_key)
_submerged_seconds.erase(player_key)
if _tracked_players.is_empty():
set_physics_process(false)

View file

@ -163,6 +163,7 @@ location_tags = Array[StringName]([&"starter_pond", &"pond"])
selection_priority = 1
recovery_entry_height_reference = 1
recovery_entry_depth_threshold = 0.1
recovery_entry_confirmation_seconds = 0.2
[node name="VisualWater" type="MeshInstance3D" parent="WaterBodies/Pond" unique_id=1034265960]
material_override = ExtResource("19_fresh_water")

View file

@ -80,6 +80,11 @@ var recovery_entry_depth_threshold: float = 0.35:
set(value):
recovery_entry_depth_threshold = clampf(value, 0.0, 2.0)
_sync_owned_nodes()
@export_range(0.0, 1.0, 0.05)
var recovery_entry_confirmation_seconds: float = 0.0:
set(value):
recovery_entry_confirmation_seconds = clampf(value, 0.0, 1.0)
_sync_owned_nodes()
@export_range(0.1, 20.0, 0.1, "or_greater", "suffix:m")
var recovery_depth: float = 4.8:
set(value):
@ -173,6 +178,9 @@ func _sync_owned_nodes() -> void:
recovery_region.entry_depth_threshold = (
recovery_entry_depth_threshold
)
recovery_region.entry_confirmation_seconds = (
recovery_entry_confirmation_seconds
)
if uses_polygon and _sync_polygon_collision_shapes(
recovery_region,
recovery_shape_node,