class_name PlayerCamera3D extends Node3D @export var follow_target : Node3D @export_range(0.0, 5.0, 0.05) var follow_max_distance : float = 1.0 @export_range(0.05, 20.0, 0.05) var follow_speed : float = 1.0 @export var follow_distance_curve : Curve @export var animation_tree : AnimationTree @export_category("Nodes") @export var camera : Camera3D @export var state_chart : StateChart @export var gimbal_x : Node3D @export var gimbal_y : Node3D @export_category("Input Settings") @export var _camera_movement_speed : Vector2 = Vector2.ONE @export var _camera_accelerate_speed : float = 1.0 @export_category("Input Resources") @export var _camera_movement_resource : InputResource var _reset_orientation : Vector2 = Vector2.ZERO var _target_camera_orientation : Vector2 = Vector2.ZERO var _debug_input_resource : InputResource func _ready() -> void: _reset_orientation = Vector2(gimbal_y.rotation.y, gimbal_x.rotation.x) if follow_target: global_position = follow_target.global_position _target_camera_orientation = _reset_orientation InputHandler.add_input_resource(self, _camera_movement_resource) _debug_input_resource = load("uid://xh7ux5jkfxle") InputHandler.add_input_resource(self, _debug_input_resource) top_level = true func _physics_process(_delta:float) -> void: gimbal_y.rotation.y = lerp_angle(gimbal_y.rotation.y, -_target_camera_orientation.x, _camera_accelerate_speed * _delta) gimbal_x.rotation.x = lerp_angle(gimbal_x.rotation.x, _target_camera_orientation.y, _camera_accelerate_speed * _delta) if follow_target: var max_position : Vector3 = (global_position - follow_target.global_position).normalized() * follow_max_distance global_position = lerp(global_position, follow_target.global_position, follow_distance_curve.sample_baked(max_position.length()) * follow_speed * _delta) if global_position.distance_squared_to(follow_target.global_position) > (follow_target.global_position + max_position).distance_squared_to(follow_target.global_position): global_position = (follow_target.global_position + max_position) func _on_camera_rotate_2d(_delta:float, _vector:Vector2) -> void: _on_camera_rotate(_delta, _vector) func _on_camera_rotate_mouse(_delta:float, _vector:Vector2) -> void: _on_camera_rotate(_delta, _vector) func _on_camera_rotate(_delta:float, _vector:Vector2) -> void: _target_camera_orientation += _vector * _camera_movement_speed * _delta const rotation_limit = (PI / 2.0) - 0.075 _target_camera_orientation.y = clamp(_target_camera_orientation.y, -rotation_limit, rotation_limit) func _on_camera_reset_pressed() -> void: _target_camera_orientation = _reset_orientation _target_camera_orientation.x -= follow_target.global_rotation.y func _on___debug_show_performance_pressed() -> void: DebugMenu.visible = !DebugMenu.visible func _on___debug_debugdraw_disabled_pressed() -> void: get_viewport().debug_draw = Viewport.DEBUG_DRAW_DISABLED func _on___debug_debugdraw_wireframe_pressed() -> void: get_viewport().debug_draw = Viewport.DEBUG_DRAW_WIREFRAME func _on___debug_debugdraw_normalbuffer_pressed() -> void: get_viewport().debug_draw = Viewport.DEBUG_DRAW_NORMAL_BUFFER func _on___debug_debugdraw_overdraw_pressed() -> void: get_viewport().debug_draw = Viewport.DEBUG_DRAW_OVERDRAW func _on___debug_debugdraw_ssao_pressed() -> void: get_viewport().debug_draw = Viewport.DEBUG_DRAW_SSAO func _on___debug_debugdraw_sdfgi_pressed() -> void: get_viewport().debug_draw = Viewport.DEBUG_DRAW_SDFGI func _on___debug_debugdraw_ssil_pressed() -> void: get_viewport().debug_draw = Viewport.DEBUG_DRAW_SSIL func _on_standard_state_entered() -> void: InputHandler.add_input_resource(self, _camera_movement_resource) _on_camera_reset_pressed() func _on_slice_time_state_entered() -> void: InputHandler.remove_input_resource(self, _camera_movement_resource) _on_camera_reset_pressed() animation_tree["parameters/playback"].travel("slice_time_zoom_in") func _on_slice_time_state_exited() -> void: animation_tree["parameters/playback"].travel("standard_zoom") func _on_slice_time_state_physics_processing(_delta:float) -> void: gimbal_y.global_rotation.y = follow_target.global_rotation.y