Add data-driven fish selection and catch showcase
This commit is contained in:
parent
ae2f724fe2
commit
bd2768b676
39 changed files with 1226 additions and 58 deletions
348
player/player.gd
348
player/player.gd
|
|
@ -2,6 +2,20 @@ class_name Player
|
|||
extends CharacterBody3D
|
||||
|
||||
const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
||||
const CollectionLogType = preload("res://collection/collection_log.gd")
|
||||
const FishCatchType = preload("res://fish/fish_catch.gd")
|
||||
|
||||
class ShowcaseCameraSnapshot:
|
||||
extends RefCounted
|
||||
|
||||
var yaw_transform: Transform3D
|
||||
var yaw_rotation: Vector3
|
||||
var pitch_rotation: Vector3
|
||||
var spring_length: float
|
||||
var target_zoom: float
|
||||
var camera_input_enabled: bool
|
||||
var camera_dragging: bool
|
||||
|
||||
|
||||
@export_category("Movement")
|
||||
@export var walk_speed: float = 5.0
|
||||
|
|
@ -18,6 +32,15 @@ const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
|||
@export_range(0.01, 2.0, 0.01) var reel_speed: float = 0.32
|
||||
@export_range(1, 100, 1) var click_power: int = 1
|
||||
|
||||
@export_category("Showcase")
|
||||
@export_range(0.05, 1.0, 0.01) var showcase_turn_duration: float = 0.28
|
||||
@export_range(0.05, 1.0, 0.01) var showcase_restore_duration: float = 0.24
|
||||
@export_range(0.05, 1.5, 0.01) var showcase_camera_transition_duration: float = 0.42
|
||||
@export_range(-180.0, 180.0, 1.0) var showcase_camera_yaw_offset: float = 180.0
|
||||
@export_range(-80.0, 80.0, 1.0) var showcase_camera_pitch: float = -8.0
|
||||
@export_range(1.0, 10.0, 0.1) var showcase_camera_zoom_distance: float = 3.6
|
||||
@export_range(0.5, 3.0, 0.05) var showcase_camera_target_height: float = 1.45
|
||||
|
||||
@export_category("Camera")
|
||||
@export var mouse_sensitivity: float = 0.005
|
||||
@export var controller_camera_speed: float = 2.5
|
||||
|
|
@ -35,14 +58,27 @@ const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
|||
@onready var _spring_arm: SpringArm3D = %SpringArm3D
|
||||
@onready var _camera: Camera3D = %Camera3D
|
||||
@onready var inventory: FishInventoryType = %Inventory
|
||||
@onready var collection_log: CollectionLogType = %CollectionLog
|
||||
@onready var _cast_origin: Marker3D = %CastOrigin
|
||||
@onready var _fishing_rod: Node3D = %FishingRod
|
||||
@onready var _fishing_rod_tip: Marker3D = %FishingRodTip
|
||||
@onready var _catch_display: Node3D = %CatchDisplay
|
||||
@onready var _catch_sprite: Sprite3D = %CatchSprite
|
||||
|
||||
var _gravity: float = float(ProjectSettings.get_setting("physics/3d/default_gravity"))
|
||||
var _camera_dragging: bool = false
|
||||
var _camera_input_enabled: bool = true
|
||||
var _movement_enabled: bool = true
|
||||
var _target_zoom: float = 5.0
|
||||
var _showcase_rod_visibility: bool = true
|
||||
var _showcase_rod_state_stored: bool = false
|
||||
var _showcase_visual_rotation: Vector3
|
||||
var _showcase_visual_rotation_stored: bool = false
|
||||
var _showcase_turn_tween: Tween
|
||||
var _showcase_restore_tween: Tween
|
||||
var _showcase_camera_tween: Tween
|
||||
var _showcase_camera_snapshot: ShowcaseCameraSnapshot
|
||||
var _showcase_restore_generation: int = 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -98,26 +134,40 @@ func _process(delta: float) -> void:
|
|||
if not local_control_enabled:
|
||||
return
|
||||
|
||||
if _camera_dragging and not Input.is_action_pressed("camera_drag"):
|
||||
if (
|
||||
_camera_input_enabled
|
||||
and _camera_dragging
|
||||
and not Input.is_action_pressed("camera_drag")
|
||||
):
|
||||
_camera_dragging = false
|
||||
|
||||
var stick: Vector2 = Vector2(
|
||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_X),
|
||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y)
|
||||
)
|
||||
if stick.length() > controller_camera_deadzone:
|
||||
var adjusted_strength: float = (
|
||||
(stick.length() - controller_camera_deadzone)
|
||||
/ (1.0 - controller_camera_deadzone)
|
||||
if _camera_input_enabled:
|
||||
var stick: Vector2 = Vector2(
|
||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_X),
|
||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y)
|
||||
)
|
||||
_rotate_camera(stick.normalized() * adjusted_strength * controller_camera_speed * delta)
|
||||
if stick.length() > controller_camera_deadzone:
|
||||
var adjusted_strength: float = (
|
||||
(stick.length() - controller_camera_deadzone)
|
||||
/ (1.0 - controller_camera_deadzone)
|
||||
)
|
||||
_rotate_camera(
|
||||
stick.normalized()
|
||||
* adjusted_strength
|
||||
* controller_camera_speed
|
||||
* delta
|
||||
)
|
||||
|
||||
var zoom_weight: float = 1.0 - exp(-zoom_smoothing * delta)
|
||||
_spring_arm.spring_length = lerpf(_spring_arm.spring_length, _target_zoom, zoom_weight)
|
||||
var zoom_weight: float = 1.0 - exp(-zoom_smoothing * delta)
|
||||
_spring_arm.spring_length = lerpf(
|
||||
_spring_arm.spring_length,
|
||||
_target_zoom,
|
||||
zoom_weight
|
||||
)
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if not local_control_enabled:
|
||||
if not local_control_enabled or not _camera_input_enabled:
|
||||
return
|
||||
|
||||
if event.is_action("camera_drag"):
|
||||
|
|
@ -192,6 +242,278 @@ func get_cast_origin_position() -> Vector3:
|
|||
return _cast_origin.global_position
|
||||
|
||||
|
||||
func begin_catch_showcase(fish_catch: FishCatchType) -> void:
|
||||
if fish_catch == null or not fish_catch.is_valid():
|
||||
return
|
||||
_kill_showcase_camera_tween()
|
||||
_kill_showcase_restore_tween()
|
||||
_capture_showcase_camera_snapshot()
|
||||
if not _showcase_visual_rotation_stored:
|
||||
_showcase_visual_rotation = _visuals.rotation
|
||||
_showcase_visual_rotation_stored = true
|
||||
var showcase_camera_position: Vector3 = _begin_showcase_camera_transition()
|
||||
_turn_showcase_toward_position(showcase_camera_position)
|
||||
if not _showcase_rod_state_stored:
|
||||
_showcase_rod_visibility = _fishing_rod.visible
|
||||
_showcase_rod_state_stored = true
|
||||
_fishing_rod.visible = false
|
||||
_catch_sprite.texture = fish_catch.fish.display_texture
|
||||
_catch_display.scale = Vector3.ONE * fish_catch.display_scale
|
||||
_catch_display.visible = _catch_sprite.texture != null
|
||||
|
||||
|
||||
func end_catch_showcase(
|
||||
restored_callback: Callable = Callable(),
|
||||
immediate: bool = false,
|
||||
) -> void:
|
||||
_kill_showcase_turn_tween()
|
||||
_kill_showcase_camera_tween()
|
||||
_kill_showcase_restore_tween()
|
||||
_catch_display.visible = false
|
||||
_catch_display.scale = Vector3.ONE
|
||||
_catch_sprite.texture = null
|
||||
if _showcase_rod_state_stored:
|
||||
_fishing_rod.visible = _showcase_rod_visibility
|
||||
_showcase_rod_visibility = true
|
||||
_showcase_rod_state_stored = false
|
||||
if (
|
||||
not _showcase_visual_rotation_stored
|
||||
and _showcase_camera_snapshot == null
|
||||
):
|
||||
if restored_callback.is_valid():
|
||||
restored_callback.call()
|
||||
return
|
||||
if immediate:
|
||||
_complete_showcase_restore(restored_callback)
|
||||
return
|
||||
|
||||
var current_rotation: Vector3 = _visuals.rotation
|
||||
var restore_target: Vector3 = _showcase_visual_rotation
|
||||
restore_target.y = (
|
||||
current_rotation.y
|
||||
+ wrapf(
|
||||
_showcase_visual_rotation.y - current_rotation.y,
|
||||
-PI,
|
||||
PI
|
||||
)
|
||||
)
|
||||
var restore_generation: int = _showcase_restore_generation
|
||||
_showcase_restore_tween = create_tween()
|
||||
_showcase_restore_tween.set_parallel(true)
|
||||
_showcase_restore_tween.set_trans(Tween.TRANS_QUAD)
|
||||
_showcase_restore_tween.set_ease(Tween.EASE_IN_OUT)
|
||||
if _showcase_visual_rotation_stored:
|
||||
_showcase_restore_tween.tween_property(
|
||||
_visuals,
|
||||
"rotation",
|
||||
restore_target,
|
||||
maxf(showcase_restore_duration, 0.05)
|
||||
)
|
||||
if _showcase_camera_snapshot != null:
|
||||
var camera_yaw_target: Vector3 = (
|
||||
_showcase_camera_snapshot.yaw_rotation
|
||||
)
|
||||
camera_yaw_target.y = (
|
||||
_camera_yaw.rotation.y
|
||||
+ wrapf(
|
||||
camera_yaw_target.y - _camera_yaw.rotation.y,
|
||||
-PI,
|
||||
PI
|
||||
)
|
||||
)
|
||||
var camera_duration: float = maxf(
|
||||
showcase_camera_transition_duration,
|
||||
0.05
|
||||
)
|
||||
_showcase_restore_tween.tween_property(
|
||||
_camera_yaw,
|
||||
"rotation",
|
||||
camera_yaw_target,
|
||||
camera_duration
|
||||
)
|
||||
_showcase_restore_tween.tween_property(
|
||||
_camera_yaw,
|
||||
"position",
|
||||
_showcase_camera_snapshot.yaw_transform.origin,
|
||||
camera_duration
|
||||
)
|
||||
_showcase_restore_tween.tween_property(
|
||||
_camera_pitch,
|
||||
"rotation",
|
||||
_showcase_camera_snapshot.pitch_rotation,
|
||||
camera_duration
|
||||
)
|
||||
_showcase_restore_tween.tween_property(
|
||||
_spring_arm,
|
||||
"spring_length",
|
||||
_showcase_camera_snapshot.spring_length,
|
||||
camera_duration
|
||||
)
|
||||
_showcase_restore_tween.finished.connect(
|
||||
_on_showcase_restore_finished.bind(
|
||||
restore_generation,
|
||||
restored_callback
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
func _turn_showcase_toward_position(target_position: Vector3) -> void:
|
||||
_kill_showcase_turn_tween()
|
||||
var camera_direction: Vector3 = (
|
||||
target_position - _visuals.global_position
|
||||
)
|
||||
camera_direction.y = 0.0
|
||||
if camera_direction.is_zero_approx():
|
||||
return
|
||||
camera_direction = camera_direction.normalized()
|
||||
var target_world_yaw: float = atan2(
|
||||
-camera_direction.x,
|
||||
-camera_direction.z
|
||||
)
|
||||
var target_local_yaw: float = target_world_yaw - global_rotation.y
|
||||
var current_yaw: float = _visuals.rotation.y
|
||||
var shortest_target_yaw: float = (
|
||||
current_yaw
|
||||
+ wrapf(target_local_yaw - current_yaw, -PI, PI)
|
||||
)
|
||||
_showcase_turn_tween = create_tween()
|
||||
_showcase_turn_tween.set_trans(Tween.TRANS_QUAD)
|
||||
_showcase_turn_tween.set_ease(Tween.EASE_IN_OUT)
|
||||
_showcase_turn_tween.tween_property(
|
||||
_visuals,
|
||||
"rotation:y",
|
||||
shortest_target_yaw,
|
||||
maxf(showcase_turn_duration, 0.05)
|
||||
)
|
||||
_showcase_turn_tween.finished.connect(_on_showcase_turn_finished)
|
||||
|
||||
|
||||
func _kill_showcase_turn_tween() -> void:
|
||||
if _showcase_turn_tween != null and _showcase_turn_tween.is_valid():
|
||||
_showcase_turn_tween.kill()
|
||||
_showcase_turn_tween = null
|
||||
|
||||
|
||||
func _kill_showcase_restore_tween() -> void:
|
||||
if _showcase_restore_tween != null and _showcase_restore_tween.is_valid():
|
||||
_showcase_restore_tween.kill()
|
||||
_showcase_restore_tween = null
|
||||
_showcase_restore_generation += 1
|
||||
|
||||
|
||||
func _kill_showcase_camera_tween() -> void:
|
||||
if _showcase_camera_tween != null and _showcase_camera_tween.is_valid():
|
||||
_showcase_camera_tween.kill()
|
||||
_showcase_camera_tween = null
|
||||
|
||||
|
||||
func _on_showcase_turn_finished() -> void:
|
||||
_showcase_turn_tween = null
|
||||
|
||||
|
||||
func _on_showcase_restore_finished(
|
||||
restore_generation: int,
|
||||
restored_callback: Callable,
|
||||
) -> void:
|
||||
if restore_generation != _showcase_restore_generation:
|
||||
return
|
||||
_showcase_restore_tween = null
|
||||
_complete_showcase_restore(restored_callback)
|
||||
|
||||
|
||||
func _complete_showcase_restore(
|
||||
restored_callback: Callable,
|
||||
) -> void:
|
||||
if _showcase_visual_rotation_stored:
|
||||
_visuals.rotation = _showcase_visual_rotation
|
||||
_showcase_visual_rotation = Vector3.ZERO
|
||||
_showcase_visual_rotation_stored = false
|
||||
if _showcase_camera_snapshot != null:
|
||||
_camera_yaw.transform = _showcase_camera_snapshot.yaw_transform
|
||||
_camera_pitch.rotation = _showcase_camera_snapshot.pitch_rotation
|
||||
_spring_arm.spring_length = _showcase_camera_snapshot.spring_length
|
||||
_target_zoom = _showcase_camera_snapshot.target_zoom
|
||||
_camera_input_enabled = (
|
||||
_showcase_camera_snapshot.camera_input_enabled
|
||||
)
|
||||
_camera_dragging = _showcase_camera_snapshot.camera_dragging
|
||||
_showcase_camera_snapshot = null
|
||||
if restored_callback.is_valid():
|
||||
restored_callback.call()
|
||||
|
||||
|
||||
func _capture_showcase_camera_snapshot() -> void:
|
||||
if _showcase_camera_snapshot != null:
|
||||
return
|
||||
_showcase_camera_snapshot = ShowcaseCameraSnapshot.new()
|
||||
_showcase_camera_snapshot.yaw_transform = _camera_yaw.transform
|
||||
_showcase_camera_snapshot.yaw_rotation = _camera_yaw.rotation
|
||||
_showcase_camera_snapshot.pitch_rotation = _camera_pitch.rotation
|
||||
_showcase_camera_snapshot.spring_length = _spring_arm.spring_length
|
||||
_showcase_camera_snapshot.target_zoom = _target_zoom
|
||||
_showcase_camera_snapshot.camera_input_enabled = _camera_input_enabled
|
||||
_showcase_camera_snapshot.camera_dragging = _camera_dragging
|
||||
_camera_input_enabled = false
|
||||
_camera_dragging = false
|
||||
|
||||
|
||||
func _begin_showcase_camera_transition() -> Vector3:
|
||||
var target_world_yaw: float = (
|
||||
_visuals.global_rotation.y
|
||||
+ deg_to_rad(showcase_camera_yaw_offset)
|
||||
)
|
||||
var target_local_yaw: float = target_world_yaw - global_rotation.y
|
||||
var shortest_target_yaw: float = (
|
||||
_camera_yaw.rotation.y
|
||||
+ wrapf(
|
||||
target_local_yaw - _camera_yaw.rotation.y,
|
||||
-PI,
|
||||
PI
|
||||
)
|
||||
)
|
||||
var target_pitch: float = deg_to_rad(showcase_camera_pitch)
|
||||
var target_position: Vector3 = _camera_yaw.position
|
||||
target_position.y = showcase_camera_target_height
|
||||
var target_zoom: float = maxf(showcase_camera_zoom_distance, 0.1)
|
||||
var camera_duration: float = maxf(
|
||||
showcase_camera_transition_duration,
|
||||
0.05
|
||||
)
|
||||
_showcase_camera_tween = create_tween()
|
||||
_showcase_camera_tween.set_parallel(true)
|
||||
_showcase_camera_tween.set_trans(Tween.TRANS_QUAD)
|
||||
_showcase_camera_tween.set_ease(Tween.EASE_IN_OUT)
|
||||
_showcase_camera_tween.tween_property(
|
||||
_camera_yaw,
|
||||
"rotation:y",
|
||||
shortest_target_yaw,
|
||||
camera_duration
|
||||
)
|
||||
_showcase_camera_tween.tween_property(
|
||||
_camera_yaw,
|
||||
"position:y",
|
||||
target_position.y,
|
||||
camera_duration
|
||||
)
|
||||
_showcase_camera_tween.tween_property(
|
||||
_camera_pitch,
|
||||
"rotation:x",
|
||||
target_pitch,
|
||||
camera_duration
|
||||
)
|
||||
_showcase_camera_tween.tween_property(
|
||||
_spring_arm,
|
||||
"spring_length",
|
||||
target_zoom,
|
||||
camera_duration
|
||||
)
|
||||
|
||||
var horizontal_offset: Vector3 = (
|
||||
Basis(Vector3.UP, target_world_yaw).z * target_zoom
|
||||
)
|
||||
return global_position + target_position + horizontal_offset
|
||||
|
||||
|
||||
func get_facing_direction() -> Vector3:
|
||||
var facing: Vector3 = -_visuals.global_basis.z
|
||||
facing.y = 0.0
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
[gd_scene load_steps=10 format=3]
|
||||
[gd_scene load_steps=11 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://player/player.gd" id="1_script"]
|
||||
[ext_resource type="Script" path="res://inventory/fish_inventory.gd" id="2_inventory"]
|
||||
[ext_resource type="Script" path="res://collection/collection_log.gd" id="3_collection"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="PlayerShape"]
|
||||
radius = 0.45
|
||||
|
|
@ -73,6 +74,26 @@ position = Vector3(0, 0.9, 0)
|
|||
unique_name_in_owner = true
|
||||
script = ExtResource("2_inventory")
|
||||
|
||||
[node name="CollectionLog" type="Node" parent="."]
|
||||
unique_name_in_owner = true
|
||||
script = ExtResource("3_collection")
|
||||
|
||||
[node name="CatchDisplayAnchor" type="Marker3D" parent="Visuals"]
|
||||
unique_name_in_owner = true
|
||||
position = Vector3(0, 1.45, -1.15)
|
||||
|
||||
[node name="CatchDisplay" type="Node3D" parent="Visuals/CatchDisplayAnchor"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
||||
[node name="CatchSprite" type="Sprite3D" parent="Visuals/CatchDisplayAnchor/CatchDisplay"]
|
||||
unique_name_in_owner = true
|
||||
pixel_size = 0.012
|
||||
billboard = 1
|
||||
shaded = false
|
||||
double_sided = true
|
||||
texture_filter = 0
|
||||
|
||||
[node name="CameraYaw" type="Node3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
position = Vector3(0, 1.35, 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue