xiandie/scene/ground/camera/camera_focus_marker.gd

152 lines
4.5 KiB
GDScript3
Raw Normal View History

class_name CameraFocusMarker extends Camera2D
2024-12-23 01:29:31 +00:00
@export var focusing_node: Node2D
@export var force_offset := Vector2.ZERO
@export_group("Status")
@export var lock_horizontal = true
@export_group("Config")
@export var half_screen_size := Vector2(564, 240) / 2.0
@export var shaded_height := 38
@export_group("Shake", "shake_")
2025-03-17 14:12:53 +00:00
@export var shake_strength := 0.0
@export var shake_recovery_speed := 4.0
# @export_group("Limit", "limit_")
# @export var limit_left := 0.0
# @export var limit_right := 564.0
# @export var limit_top := 0
# @export var limit_bottom := 316.0
@export var zoom_ratio := 1.0
var speed := 3.0
var _tweeked_position := Vector2.ZERO
var zoom_tween: Tween
var focus_offset := Vector2.ZERO
2025-03-17 14:12:53 +00:00
var shaked_offset := Vector2.ZERO
func _ready() -> void:
if not focusing_node:
push_error("Focusing node not found")
reset_position_immediately()
func _enter_tree() -> void:
if is_node_ready():
reset_position_immediately()
func shake_camera(strength := 7.0):
2025-03-17 14:12:53 +00:00
shake_strength = strength
func reset_position_immediately():
if focusing_node:
global_position = focusing_node.global_position + _tweeked_position + force_offset
func tweak_position(velocity, facing_direction):
var ideal_x = facing_direction.x * min(50.0, 0.5 * abs(velocity.x))
var current_x = _tweeked_position.x
var delta = ideal_x - current_x
if abs(delta) > 10.0:
_tweeked_position.x = move_toward(current_x, ideal_x, speed * 2.0)
if lock_horizontal:
global_position.y = 0
_tweeked_position.y = 0
else:
_tweeked_position.y = facing_direction.y * abs(velocity.y) * 0.2
func _physics_process(delta: float) -> void:
if not focusing_node:
return
# set camera's position
var target_position = (
2025-03-17 14:12:53 +00:00
focusing_node.global_position + _tweeked_position + force_offset + focus_offset + shaked_offset
)
if focusing_node is MainPlayer:
# player 的焦点在脚底,所以需要偏移 player 的高度。注意 y 轴是向下的,所以是减去 player 的高度
target_position.y -= focusing_node.current_animation_config.os_height * 0.7
# easing with speed
var new_position = lerp(global_position, target_position, speed * delta)
# var new_position = global_position + (target_position - global_position) * speed * delta
# clamp the position
var margin = half_screen_size / zoom_ratio
# var margin = half_screen_size
margin.y += shaded_height
new_position.x = clamp(new_position.x, limit_left + margin.x, limit_right - margin.x)
new_position.y = clamp(new_position.y, limit_top + margin.y, limit_bottom - margin.y)
global_position = new_position
# var taget_zoom = lerpf(zoom.x, zoom_ratio, speed * delta)
# zoom = Vector2(taget_zoom, taget_zoom)
zoom = Vector2(zoom_ratio, zoom_ratio)
2025-03-17 14:12:53 +00:00
# handle shake, via _shaked_position
if shake_strength > 0.0:
shake_strength = lerpf(shake_strength, 0.0, shake_recovery_speed * delta)
shaked_offset = Vector2(randf_range(-shake_strength, shake_strength), randf_range(-shake_strength, shake_strength))
global_position += shaked_offset
func tween_zoom(ratio: float, duration := 1.5):
if zoom_tween and zoom_tween.is_running():
zoom_tween.kill()
zoom_tween = create_tween()
(
zoom_tween
. tween_property(self, "zoom_ratio", ratio, duration)
. set_trans(Tween.TRANS_SINE)
. set_ease(Tween.EASE_IN_OUT)
. from(zoom_ratio)
)
# if refocus:
# zooming_and_focus_start_position = global_position
# (
# zoom_tween
# . parallel()
# . tween_property(self, "zooming_and_focus_progress", 1.0, duration)
# . from(0.0)
# . set_trans(Tween.TRANS_SINE)
# . set_ease(Tween.EASE_IN_OUT)
# )
var tween_focus: Tween
func focus_node(node: Node2D, duration := 0.0) -> void:
if focusing_node == node:
return
if not node:
focusing_node = null
return
if duration > 0.0:
focus_offset = global_position - node.global_position
if tween_focus and tween_focus.is_running():
tween_focus.kill()
tween_focus = create_tween()
(
tween_focus
. tween_property(self, "focus_offset", Vector2.ZERO, duration)
. set_trans(Tween.TRANS_SINE)
. set_ease(Tween.EASE_IN_OUT)
)
focusing_node = node
# var exited := false
# var exit_position: Vector2
# var enter_tree_tween: Tween
# func _exit_tree() -> void:
# exit_position = global_position
# exited = true
# func _enter_tree() -> void:
# if exited and is_node_ready():
# exited = false
# if enter_tree_tween and enter_tree_tween.is_running():
# enter_tree_tween.kill()
# enter_tree_tween = create_tween()
# global_position = exit_position
# enter_tree_tween.tween_property(self, "position", Vector2.ZERO, 0.2).set_trans(
# Tween.TRANS_CUBIC
# )