forked from woofmeow/straywild
feat: add animated net gathering
This commit is contained in:
parent
b252b2f20c
commit
f0ddcccaad
38 changed files with 1298 additions and 76 deletions
|
|
@ -11,3 +11,4 @@ required_tool_id = &"crab_net"
|
|||
surface_materials = Array[StringName]([&"sand"])
|
||||
minimum_surface_y = -0.8
|
||||
population = 4
|
||||
sprite_pixel_size = 0.00025
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ scare_radius = 2.8
|
|||
capture_radius = 0.7
|
||||
interaction_range = 2.6
|
||||
charge_duration = 2.0
|
||||
sprite_pixel_size = 0.001
|
||||
sprite_pixel_size = 0.00025
|
||||
sprite_tilt_degrees = -45.0
|
||||
capture_respawn_min_seconds = 480.0
|
||||
capture_respawn_max_seconds = 720.0
|
||||
|
|
|
|||
|
|
@ -11,3 +11,4 @@ required_tool_id = &"crab_net"
|
|||
surface_materials = Array[StringName]([&"sand"])
|
||||
minimum_surface_y = -0.5
|
||||
population = 4
|
||||
sprite_pixel_size = 0.00025
|
||||
|
|
|
|||
|
|
@ -11,3 +11,4 @@ required_tool_id = &"crab_net"
|
|||
surface_materials = Array[StringName]([&"sand"])
|
||||
minimum_surface_y = 0.08
|
||||
population = 4
|
||||
sprite_pixel_size = 0.00025
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const FishQualityType = preload("res://fish/fish_quality.gd")
|
|||
@export_range(0.1, 5.0, 0.05) var capture_radius: float = 0.7
|
||||
@export_range(0.1, 10.0, 0.05) var interaction_range: float = 2.6
|
||||
@export_range(0.1, 10.0, 0.05) var charge_duration: float = 2.0
|
||||
@export_range(0.1, 5.0, 0.01) var sprite_pixel_size: float = 0.001
|
||||
@export_range(0.0001, 0.01, 0.00005) var sprite_pixel_size: float = 0.001
|
||||
@export_range(-90.0, 90.0, 1.0) var sprite_tilt_degrees: float = -45.0
|
||||
@export_category("Respawn Budget")
|
||||
@export_range(0.0, 3600.0, 1.0) var capture_respawn_min_seconds: float = 480.0
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ const NetworkWorldSpawnServiceType = preload(
|
|||
signal status_changed(message: String)
|
||||
|
||||
@export_range(0.5, 5.0, 0.05) var marker_distance: float = 1.7
|
||||
@export_range(0.1, 2.0, 0.05) var marker_radius: float = 0.7
|
||||
@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
|
||||
@export_flags_3d_physics var terrain_collision_mask: int = 1
|
||||
@export_range(0.5, 20.0, 0.5) var ray_height: float = 5.0
|
||||
@export_range(0.5, 20.0, 0.5) var ray_depth: float = 8.0
|
||||
|
|
@ -112,6 +114,13 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||
if not event.is_action("fish_primary"):
|
||||
return
|
||||
if event.is_pressed():
|
||||
if (
|
||||
_gameplay_input_enabled
|
||||
and _player != null
|
||||
and _player.release_net_strike_hold()
|
||||
):
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
if (
|
||||
_charging
|
||||
or not _gameplay_input_enabled
|
||||
|
|
@ -133,17 +142,20 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||
)
|
||||
_update_marker_target()
|
||||
_update_target_entity()
|
||||
_player.begin_net_draw_visual()
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
if not _charging:
|
||||
return
|
||||
var fully_charged: bool = _charge_elapsed >= _charge_duration
|
||||
if (
|
||||
var valid_capture: bool = (
|
||||
fully_charged
|
||||
and _marker_has_surface
|
||||
and not _target_entity_id.is_empty()
|
||||
and _player.is_sneaking()
|
||||
):
|
||||
)
|
||||
_player.play_net_strike_visual()
|
||||
if valid_capture:
|
||||
_service.finish_local_interaction(
|
||||
_request_id,
|
||||
_target_entity_id,
|
||||
|
|
@ -151,6 +163,7 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||
)
|
||||
else:
|
||||
_service.cancel_local_interaction(_request_id)
|
||||
_player.resolve_net_strike_visual(false)
|
||||
_reset_charge_state()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
|
@ -167,23 +180,82 @@ func _update_marker_target() -> void:
|
|||
if facing.is_zero_approx():
|
||||
return
|
||||
facing = facing.normalized()
|
||||
var probe_origin: Vector3 = _player.get_body_center_position()
|
||||
var probe_direction: Vector3 = _get_surface_probe_direction(facing)
|
||||
var forward_hit: Dictionary = _cast_marker_ray(
|
||||
probe_origin,
|
||||
probe_origin
|
||||
+ probe_direction
|
||||
* (marker_distance + forward_probe_extra_distance),
|
||||
)
|
||||
if _apply_marker_surface(forward_hit, facing):
|
||||
return
|
||||
var query_center: Vector3 = _player.global_position + facing * marker_distance
|
||||
var query := PhysicsRayQueryParameters3D.create(
|
||||
var ground_hit: Dictionary = _cast_marker_ray(
|
||||
query_center + Vector3.UP * ray_height,
|
||||
query_center - Vector3.UP * ray_depth,
|
||||
)
|
||||
_apply_marker_surface(ground_hit, facing)
|
||||
|
||||
|
||||
func _get_surface_probe_direction(facing: Vector3) -> Vector3:
|
||||
var vertical_aim: float = 0.0
|
||||
var camera := _player.get_active_gameplay_camera()
|
||||
if camera != null:
|
||||
vertical_aim = clampf((-camera.global_basis.z).y, -0.75, 0.75)
|
||||
return Vector3(facing.x, vertical_aim, facing.z).normalized()
|
||||
|
||||
|
||||
func _cast_marker_ray(from: Vector3, to: Vector3) -> Dictionary:
|
||||
var query := PhysicsRayQueryParameters3D.create(
|
||||
from,
|
||||
to,
|
||||
terrain_collision_mask,
|
||||
[_player.get_rid()],
|
||||
)
|
||||
query.collide_with_areas = false
|
||||
query.collide_with_bodies = true
|
||||
var hit: Dictionary = get_world_3d().direct_space_state.intersect_ray(query)
|
||||
return get_world_3d().direct_space_state.intersect_ray(query)
|
||||
|
||||
|
||||
func _apply_marker_surface(hit: Dictionary, facing: Vector3) -> bool:
|
||||
if hit.is_empty():
|
||||
return
|
||||
return false
|
||||
var position: Variant = hit.get("position")
|
||||
if typeof(position) != TYPE_VECTOR3:
|
||||
return
|
||||
_marker_position = (position as Vector3) + Vector3.UP * 0.045
|
||||
var normal_value: Variant = hit.get("normal")
|
||||
if (
|
||||
typeof(position) != TYPE_VECTOR3
|
||||
or typeof(normal_value) != TYPE_VECTOR3
|
||||
):
|
||||
return false
|
||||
var surface_normal := normal_value as Vector3
|
||||
if not surface_normal.is_finite() or surface_normal.is_zero_approx():
|
||||
return false
|
||||
surface_normal = surface_normal.normalized()
|
||||
_marker_position = (
|
||||
(position as Vector3) + surface_normal * marker_surface_offset
|
||||
)
|
||||
_marker.global_position = _marker_position
|
||||
_marker.global_basis = marker_basis_for_surface(surface_normal, facing)
|
||||
_marker_has_surface = true
|
||||
return true
|
||||
|
||||
|
||||
static func marker_basis_for_surface(
|
||||
surface_normal: Vector3,
|
||||
facing: Vector3,
|
||||
) -> Basis:
|
||||
var normal := surface_normal.normalized()
|
||||
var reference := Vector3.UP
|
||||
if absf(normal.dot(Vector3.UP)) > 0.95:
|
||||
reference = facing.normalized()
|
||||
if reference.is_zero_approx() or absf(normal.dot(reference)) > 0.95:
|
||||
reference = Vector3.FORWARD
|
||||
var x_axis := reference.cross(normal).normalized()
|
||||
if x_axis.is_zero_approx():
|
||||
x_axis = Vector3.RIGHT
|
||||
var z_axis := x_axis.cross(normal).normalized()
|
||||
return Basis(x_axis, normal, z_axis).orthonormalized()
|
||||
|
||||
|
||||
func _update_target_entity() -> void:
|
||||
|
|
@ -200,6 +272,8 @@ func _update_target_entity() -> void:
|
|||
func _cancel_charge() -> void:
|
||||
if _charging and not _request_id.is_empty() and _service != null:
|
||||
_service.cancel_local_interaction(_request_id)
|
||||
if _charging and _player != null:
|
||||
_player.cancel_net_action_visual()
|
||||
_reset_charge_state()
|
||||
|
||||
|
||||
|
|
@ -213,6 +287,8 @@ func _reset_charge_state() -> void:
|
|||
|
||||
|
||||
func _on_interaction_finished(accepted: bool, message: String) -> void:
|
||||
if _player != null:
|
||||
_player.resolve_net_strike_visual(accepted)
|
||||
_reset_charge_state()
|
||||
if not accepted or not message.is_empty():
|
||||
status_changed.emit(message)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ class_name WorldGatherable
|
|||
extends Node3D
|
||||
|
||||
const GatherableDataType = preload("res://gathering/gatherable_data.gd")
|
||||
const REFERENCE_SPRITE_PIXEL_SIZE: float = 0.001
|
||||
const REFERENCE_SPRITE_HEIGHT: float = 0.22
|
||||
|
||||
var entity_id: String = ""
|
||||
var type_id: StringName
|
||||
|
|
@ -26,6 +28,11 @@ func configure(
|
|||
if data != null and data.catch_data != null:
|
||||
_sprite.texture = data.catch_data.display_texture
|
||||
_sprite.pixel_size = data.sprite_pixel_size
|
||||
_sprite.position.y = (
|
||||
REFERENCE_SPRITE_HEIGHT
|
||||
* data.sprite_pixel_size
|
||||
/ REFERENCE_SPRITE_PIXEL_SIZE
|
||||
)
|
||||
_sprite.rotation_degrees.x = data.sprite_tilt_degrees
|
||||
apply_network_state(position, yaw, true)
|
||||
|
||||
|
|
@ -80,7 +87,7 @@ func _ensure_visual() -> void:
|
|||
return
|
||||
_sprite = Sprite3D.new()
|
||||
_sprite.name = "GatherableSprite"
|
||||
_sprite.position.y = 0.22
|
||||
_sprite.position.y = REFERENCE_SPRITE_HEIGHT
|
||||
_sprite.shaded = false
|
||||
_sprite.double_sided = true
|
||||
_sprite.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue