From 34fcb957e9796c0b3aae8f913123211e622e639f Mon Sep 17 00:00:00 2001 From: Voyager Date: Mon, 17 Aug 2026 19:06:45 -0400 Subject: [PATCH] fix: improve crab spawning and net targeting --- gathering/catalog/crab_blue.tres | 2 +- gathering/catalog/crab_brown.tres | 4 +-- gathering/catalog/crab_dungeness.tres | 2 +- gathering/catalog/crab_ghost.tres | 2 +- gathering/gathering_controller.gd | 24 +++++++++----- gathering/world_gatherable.gd | 1 + tests/gathering_marker_surface_validation.gd | 35 +++++++++++++++++++- tests/world_spawn_protocol_validation.gd | 27 +++++++++++++-- 8 files changed, 79 insertions(+), 18 deletions(-) diff --git a/gathering/catalog/crab_blue.tres b/gathering/catalog/crab_blue.tres index b2f1234..1ccabe8 100644 --- a/gathering/catalog/crab_blue.tres +++ b/gathering/catalog/crab_blue.tres @@ -11,4 +11,4 @@ required_tool_id = &"crab_net" surface_materials = Array[StringName]([&"sand"]) minimum_surface_y = -0.8 population = 4 -sprite_pixel_size = 0.00025 +sprite_pixel_size = 0.0005 diff --git a/gathering/catalog/crab_brown.tres b/gathering/catalog/crab_brown.tres index 0c140a2..83d20c8 100644 --- a/gathering/catalog/crab_brown.tres +++ b/gathering/catalog/crab_brown.tres @@ -9,7 +9,7 @@ type_id = &"crab_brown" catch_data = ExtResource("2_catch") required_tool_id = &"crab_net" surface_materials = Array[StringName]([&"sand"]) -minimum_surface_y = 0.08 +minimum_surface_y = -0.44 population = 2 movement_speed = 0.35 roam_radius = 3.5 @@ -17,7 +17,7 @@ scare_radius = 2.8 capture_radius = 0.7 interaction_range = 2.6 charge_duration = 2.0 -sprite_pixel_size = 0.00025 +sprite_pixel_size = 0.0005 sprite_tilt_degrees = -45.0 capture_respawn_min_seconds = 480.0 capture_respawn_max_seconds = 720.0 diff --git a/gathering/catalog/crab_dungeness.tres b/gathering/catalog/crab_dungeness.tres index 699210f..12eb7a6 100644 --- a/gathering/catalog/crab_dungeness.tres +++ b/gathering/catalog/crab_dungeness.tres @@ -11,4 +11,4 @@ required_tool_id = &"crab_net" surface_materials = Array[StringName]([&"sand"]) minimum_surface_y = -0.5 population = 4 -sprite_pixel_size = 0.00025 +sprite_pixel_size = 0.0005 diff --git a/gathering/catalog/crab_ghost.tres b/gathering/catalog/crab_ghost.tres index bfc164d..62ce103 100644 --- a/gathering/catalog/crab_ghost.tres +++ b/gathering/catalog/crab_ghost.tres @@ -11,4 +11,4 @@ required_tool_id = &"crab_net" surface_materials = Array[StringName]([&"sand"]) minimum_surface_y = 0.08 population = 4 -sprite_pixel_size = 0.00025 +sprite_pixel_size = 0.0005 diff --git a/gathering/gathering_controller.gd b/gathering/gathering_controller.gd index 9968412..2260c68 100644 --- a/gathering/gathering_controller.gd +++ b/gathering/gathering_controller.gd @@ -6,10 +6,13 @@ const FishingSpotType = preload("res://fishing/fishing_spot.gd") const NetworkWorldSpawnServiceType = preload( "res://network/network_world_spawn_service.gd" ) +const MARKER_INVALID_COLOR := Color(1.0, 1.0, 1.0, 1.0) +const MARKER_VALID_COLOR := Color(0.25, 0.9, 0.36, 1.0) +const MARKER_DISC_THICKNESS := 0.006 signal status_changed(message: String) -@export_range(0.5, 5.0, 0.05) var marker_distance: float = 1.7 +@export_range(0.5, 5.0, 0.05) var marker_distance: float = 0.85 @export_range(0.025, 2.0, 0.025) var marker_radius: float = 0.175 @export_range(0.0, 1.0, 0.01) var marker_surface_offset: float = 0.045 @export_range(0.0, 2.0, 0.05) var forward_probe_extra_distance: float = 0.6 @@ -296,19 +299,22 @@ func _on_interaction_finished(accepted: bool, message: String) -> void: func _build_marker() -> void: _marker_invalid_material = StandardMaterial3D.new() - _marker_invalid_material.albedo_color = Color(0.86, 0.24, 0.19, 0.9) + _marker_invalid_material.albedo_color = MARKER_INVALID_COLOR _marker_invalid_material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + _marker_invalid_material.roughness = 1.0 _marker_valid_material = StandardMaterial3D.new() - _marker_valid_material.albedo_color = Color(0.25, 0.9, 0.36, 0.95) + _marker_valid_material.albedo_color = MARKER_VALID_COLOR _marker_valid_material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - var ring := TorusMesh.new() - ring.inner_radius = marker_radius * 0.78 - ring.outer_radius = marker_radius - ring.rings = 16 - ring.ring_segments = 24 + _marker_valid_material.roughness = 1.0 + var disc := CylinderMesh.new() + disc.top_radius = marker_radius + disc.bottom_radius = marker_radius + disc.height = MARKER_DISC_THICKNESS + disc.radial_segments = 32 + disc.rings = 1 _marker = MeshInstance3D.new() _marker.name = "GatheringTargetMarker" - _marker.mesh = ring + _marker.mesh = disc _marker.material_override = _marker_invalid_material _marker.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF _marker.visible = false diff --git a/gathering/world_gatherable.gd b/gathering/world_gatherable.gd index 6db2e9d..e059df1 100644 --- a/gathering/world_gatherable.gd +++ b/gathering/world_gatherable.gd @@ -90,6 +90,7 @@ func _ensure_visual() -> void: _sprite.position.y = REFERENCE_SPRITE_HEIGHT _sprite.shaded = false _sprite.double_sided = true + _sprite.billboard = BaseMaterial3D.BILLBOARD_ENABLED _sprite.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST add_child(_sprite) diff --git a/tests/gathering_marker_surface_validation.gd b/tests/gathering_marker_surface_validation.gd index 1ae48a5..8ce3b4a 100644 --- a/tests/gathering_marker_surface_validation.gd +++ b/tests/gathering_marker_surface_validation.gd @@ -22,13 +22,36 @@ func _run() -> void: var wall := _make_surface( Vector3(2.0, 2.0, 0.1), - Vector3(0.0, 0.9, -1.5), + Vector3(0.0, 0.9, -1.1), ) root.add_child(wall) await physics_frame controller.call("_update_marker_target") var marker := controller.get("_marker") as MeshInstance3D assert(marker != null) + var disc := marker.mesh as CylinderMesh + assert(disc != null) + assert(is_equal_approx(disc.top_radius, controller.marker_radius)) + assert(is_equal_approx(disc.bottom_radius, controller.marker_radius)) + var invalid_material := controller.get( + "_marker_invalid_material" + ) as StandardMaterial3D + var valid_material := controller.get( + "_marker_valid_material" + ) as StandardMaterial3D + assert(invalid_material != null) + assert(valid_material != null) + assert(invalid_material.albedo_color == Color.WHITE) + assert(is_equal_approx(invalid_material.albedo_color.a, 1.0)) + assert(is_equal_approx(valid_material.albedo_color.a, 1.0)) + assert( + invalid_material.shading_mode + == BaseMaterial3D.SHADING_MODE_UNSHADED + ) + assert( + valid_material.shading_mode + == BaseMaterial3D.SHADING_MODE_UNSHADED + ) assert(bool(controller.get("_marker_has_surface"))) assert(marker.global_basis.y.dot(Vector3.BACK) > 0.99) @@ -44,6 +67,16 @@ func _run() -> void: assert(bool(controller.get("_marker_has_surface"))) assert(marker.global_basis.y.dot(Vector3.UP) > 0.99) assert(is_equal_approx(absf(marker.global_basis.determinant()), 1.0)) + var horizontal_marker_offset := Vector2( + marker.global_position.x - player.global_position.x, + marker.global_position.z - player.global_position.z, + ).length() + assert( + is_equal_approx( + horizontal_marker_offset, + controller.marker_distance, + ) + ) floor.queue_free() controller.queue_free() diff --git a/tests/world_spawn_protocol_validation.gd b/tests/world_spawn_protocol_validation.gd index fd00423..f433321 100644 --- a/tests/world_spawn_protocol_validation.gd +++ b/tests/world_spawn_protocol_validation.gd @@ -7,9 +7,11 @@ const FishCatalog: FishPool = preload("res://fish/pools/fish_catalog.tres") const GatheringControllerType = preload( "res://gathering/gathering_controller.gd" ) +const WorldGatherableType = preload("res://gathering/world_gatherable.gd") -const REDUCED_CRAB_PIXEL_SIZE: float = 0.00025 +const CRAB_PIXEL_SIZE: float = 0.0005 const REDUCED_CATCH_RING_RADIUS: float = 0.175 +const NET_STRIKE_MARKER_DISTANCE: float = 0.85 func _initialize() -> void: @@ -20,6 +22,7 @@ func _initialize() -> void: ) assert(NetworkWorldSpawnProtocol.SNAPSHOT_ENTITIES_PER_ENVELOPE <= 4) _validate_catalog_statuses() + _validate_billboard_presentation() _validate_envelopes() print("World spawn protocol validation: PASS") quit() @@ -36,7 +39,7 @@ func _validate_catalog_statuses() -> void: assert( is_equal_approx( brown.sprite_pixel_size, - REDUCED_CRAB_PIXEL_SIZE, + CRAB_PIXEL_SIZE, ) ) _validate_quality_behavior(brown) @@ -46,6 +49,7 @@ func _validate_catalog_statuses() -> void: assert(is_equal_approx(brown.scare_respawn_max_seconds, 90.0)) assert(is_equal_approx(brown.minimum_respawn_spacing_seconds, 180.0)) assert(brown.required_tool_id == &"crab_net") + assert(is_equal_approx(brown.minimum_surface_y, -0.44)) assert(FishCatalog.get_fish_by_id(&"crab_brown") == brown.catch_data) assert(not brown.catch_data.is_fishable()) @@ -62,7 +66,7 @@ func _validate_catalog_statuses() -> void: assert( is_equal_approx( entry.sprite_pixel_size, - REDUCED_CRAB_PIXEL_SIZE, + CRAB_PIXEL_SIZE, ) ) assert(entry.catch_data.collection_method == FishData.CollectionMethod.NET) @@ -88,9 +92,26 @@ func _validate_catalog_statuses() -> void: REDUCED_CATCH_RING_RADIUS, ) ) + assert( + is_equal_approx( + gathering_controller.marker_distance, + NET_STRIKE_MARKER_DISTANCE, + ) + ) gathering_controller.free() +func _validate_billboard_presentation() -> void: + var gatherable := WorldGatherableType.new() + gatherable.call("_ensure_visual") + var sprite := gatherable.get_node("GatherableSprite") as Sprite3D + assert(sprite != null) + assert(sprite.billboard == BaseMaterial3D.BILLBOARD_ENABLED) + assert(sprite.texture_filter == BaseMaterial3D.TEXTURE_FILTER_NEAREST) + assert(not sprite.shaded) + gatherable.free() + + func _validate_quality_behavior(entry: GatherableData) -> void: var prior_speed: float = -1.0 var prior_scare_radius: float = -1.0