WIP: refactor camera anchor system
This commit is contained in:
parent
97ea4ae12e
commit
98178a2bd2
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
#'''
|
||||
#@tool
|
||||
#extends Node
|
||||
extends Node
|
||||
#
|
||||
#@onready var camera_2d: Camera2D = %Camera2D
|
||||
#@onready var camera_shake_player: CameraShakePlayer = %CameraShakePlayer
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://cw6buluknvjj"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://djk7tg2puphgv" path="res://_camera/camera_test.gd" id="1_05blt"]
|
||||
[ext_resource type="Script" uid="uid://py4h5jxlncro" path="res://addons/reedcamera/scripts/CameraPointer.gd" id="1_e7rkk"]
|
||||
[ext_resource type="Script" uid="uid://dwr1s51svvank" path="res://addons/reedcamera/scripts/camera_tools/CameraShakeController.gd" id="2_rbequ"]
|
||||
[ext_resource type="Script" uid="uid://bhl5it46hv4n2" path="res://addons/reedcamera/scripts/camera_tools/CameraAnchorController.gd" id="4_877nu"]
|
||||
|
||||
[node name="PlateformerCamera" type="Camera2D"]
|
||||
script = ExtResource("1_05blt")
|
||||
|
||||
[node name="CameraPointer" type="Node" parent="."]
|
||||
script = ExtResource("1_e7rkk")
|
||||
metadata/_custom_type_script = "uid://py4h5jxlncro"
|
||||
|
||||
[node name="ReedCameraShakeController" type="Node" parent="CameraPointer"]
|
||||
script = ExtResource("2_rbequ")
|
||||
metadata/_custom_type_script = "uid://dwr1s51svvank"
|
||||
|
||||
[node name="ReedCameraAnchorController" type="Node" parent="CameraPointer"]
|
||||
script = ExtResource("4_877nu")
|
||||
metadata/_custom_type_script = "uid://bhl5it46hv4n2"
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
extends RemoteTransform2D
|
||||
|
||||
func _ready() -> void:
|
||||
var global_camera: Camera2D = CameraSystem.get_cached_camera()
|
||||
if not global_camera:
|
||||
push_error("[CameraFollower]:No Global Camera Founded")
|
||||
return
|
||||
remote_path = global_camera.get_path()
|
||||
pass
|
||||
#var global_camera: Camera2D = CameraSystem.get_cached_camera()
|
||||
#if not global_camera:
|
||||
#push_error("[CameraFollower]:No Global Camera Founded")
|
||||
#return
|
||||
#remote_path = global_camera.get_path()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
extends Camera2D
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("ui_accept"):
|
||||
$CameraPointer/ReedCameraShakeController.play_shake(preload("res://addons/reedcamera/_example/test_shake.tres"))
|
||||
#elif event.is_action_pressed("ui_right"):
|
||||
#self.global_position += Vector2(100,0)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://djk7tg2puphgv
|
||||
|
|
@ -78,6 +78,7 @@ unique_name_in_owner = true
|
|||
shape = SubResource("RectangleShape2D_qnulu")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
visible = false
|
||||
texture_filter = 1
|
||||
position = Vector2(0, -2)
|
||||
texture = SubResource("AtlasTexture_basl5")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://ck8m7revy150r"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://gwhff4qaouxy" path="res://_player/Avatar.tscn" id="1_irquc"]
|
||||
[ext_resource type="Texture2D" uid="uid://dted7geb331y2" path="res://_asset/ksw/character.png" id="2_350jv"]
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_350jv"]
|
||||
radius = 41.0
|
||||
height = 134.0
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_e1o4i"]
|
||||
radius = 45.0
|
||||
height = 145.0
|
||||
|
||||
[node name="Avatar" instance=ExtResource("1_irquc")]
|
||||
|
||||
[node name="CollisionShape2D" parent="." index="1"]
|
||||
visible = false
|
||||
shape = SubResource("CapsuleShape2D_350jv")
|
||||
|
||||
[node name="Sprite2D" parent="." index="2"]
|
||||
visible = true
|
||||
texture_filter = 0
|
||||
texture = ExtResource("2_350jv")
|
||||
|
||||
[node name="LocomotionComponent" parent="." index="5"]
|
||||
_can_move = false
|
||||
|
||||
[node name="CollisionShape2D" parent="HitBox" index="0"]
|
||||
visible = false
|
||||
position = Vector2(0, 0)
|
||||
shape = SubResource("CapsuleShape2D_e1o4i")
|
||||
|
||||
[editable path="LocomotionComponent/WallDetector"]
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://ck8m7revy150r"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://gwhff4qaouxy" path="res://_player/Avatar.tscn" id="1_irquc"]
|
||||
[ext_resource type="Texture2D" uid="uid://dted7geb331y2" path="res://_asset/ksw/character.png" id="2_350jv"]
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_350jv"]
|
||||
radius = 41.0
|
||||
height = 134.0
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_e1o4i"]
|
||||
radius = 45.0
|
||||
height = 145.0
|
||||
|
||||
[node name="Avatar" instance=ExtResource("1_irquc")]
|
||||
|
||||
[node name="CollisionShape2D" parent="." index="1"]
|
||||
visible = false
|
||||
shape = SubResource("CapsuleShape2D_350jv")
|
||||
|
||||
[node name="Sprite2D" parent="." index="2"]
|
||||
visible = true
|
||||
texture_filter = 0
|
||||
texture = ExtResource("2_350jv")
|
||||
|
||||
[node name="CollisionShape2D" parent="HitBox" index="0"]
|
||||
visible = false
|
||||
position = Vector2(0, 0)
|
||||
shape = SubResource("CapsuleShape2D_e1o4i")
|
||||
|
||||
[editable path="LocomotionComponent/WallDetector"]
|
||||
|
|
@ -44,8 +44,8 @@ func _enter() -> void:
|
|||
elif i == 3 or i == 7:
|
||||
csp = agent.camera_shake_preset.get("xy_light")
|
||||
|
||||
if csp:
|
||||
CameraSystem.camera_shake_player.play(csp)
|
||||
#if csp:
|
||||
#CameraSystem.camera_shake_player.play(csp)
|
||||
|
||||
if root.grap_hook_state._jump_grace_timer > 0:
|
||||
_hook_to_jump()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://b2rtcqvak066v"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://c673bap4b12fx" path="res://icon.svg" id="1_6ducv"]
|
||||
[ext_resource type="PackedScene" uid="uid://cw6buluknvjj" path="res://_camera/PlateformerCamera.tscn" id="2_owtx0"]
|
||||
|
||||
[node name="Test" type="Node2D"]
|
||||
|
||||
[node name="Icon" type="Sprite2D" parent="."]
|
||||
position = Vector2(-1, -2)
|
||||
texture = ExtResource("1_6ducv")
|
||||
|
||||
[node name="PlateformerCamera" parent="." instance=ExtResource("2_owtx0")]
|
||||
ignore_rotation = false
|
||||
position_smoothing_enabled = true
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
[gd_resource type="Resource" script_class="ReedCameraShakePreset" load_steps=2 format=3 uid="uid://wm3cmccp1ydl"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://wlqopoksgvjc" path="res://addons/reedcamera/resource/ReedCameraShakePreset.gd" id="1_8o8fw"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_8o8fw")
|
||||
amplitude = Vector2(10, 10)
|
||||
frequency = 100.0
|
||||
metadata/_custom_type_script = "uid://wlqopoksgvjc"
|
||||
|
Before Width: | Height: | Size: 869 B After Width: | Height: | Size: 869 B |
|
|
@ -3,15 +3,15 @@
|
|||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bsdmq0essfmpk"
|
||||
path="res://.godot/imported/camera_anchor_icon.svg-bc0c9f7b183031f0db701d2e858a9063.ctex"
|
||||
path="res://.godot/imported/camera_anchor_icon.svg-d54e4ec18108e371c1abc23152af31de.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://_asset/icon/camera_anchor_icon.svg"
|
||||
dest_files=["res://.godot/imported/camera_anchor_icon.svg-bc0c9f7b183031f0db701d2e858a9063.ctex"]
|
||||
source_file="res://addons/reedcamera/icon/camera_anchor_icon.svg"
|
||||
dest_files=["res://.godot/imported/camera_anchor_icon.svg-d54e4ec18108e371c1abc23152af31de.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
extends RefCounted
|
||||
class_name ReedCameraShakePlayer
|
||||
|
||||
var _preset: ReedCameraShakePreset
|
||||
var _time := 0.0
|
||||
var _strength := 0.0
|
||||
var _active := false
|
||||
|
||||
var _noise := FastNoiseLite.new()
|
||||
var _noise_seed := randi()
|
||||
|
||||
func play(preset: ReedCameraShakePreset) -> void:
|
||||
_preset = preset
|
||||
_time = 0.0
|
||||
_strength = 0.0
|
||||
_active = true
|
||||
_noise.seed = _noise_seed
|
||||
|
||||
func stop() -> void:
|
||||
_active = false
|
||||
|
||||
func is_active() -> bool:
|
||||
return _active
|
||||
|
||||
func evaluate(delta: float) -> Vector2:
|
||||
if not _active or not _preset:
|
||||
return Vector2.ZERO
|
||||
|
||||
_time += delta
|
||||
|
||||
var total := _preset.fade_in + _preset.hold + _preset.fade_out
|
||||
if _time >= total:
|
||||
_active = false
|
||||
return Vector2.ZERO
|
||||
|
||||
# ===== 强度曲线 =====
|
||||
if _time < _preset.fade_in:
|
||||
_strength = _time / _preset.fade_in
|
||||
elif _time < _preset.fade_in + _preset.hold:
|
||||
_strength = 1.0
|
||||
else:
|
||||
var t := (_time - _preset.fade_in - _preset.hold) / _preset.fade_out
|
||||
_strength = 1.0 - t
|
||||
|
||||
# ===== Noise 偏移 =====
|
||||
var shake_t := _time * _preset.frequency
|
||||
var offset := Vector2(
|
||||
_noise.get_noise_1d(shake_t),
|
||||
_noise.get_noise_1d(shake_t + 1000)
|
||||
)
|
||||
|
||||
return Vector2(
|
||||
offset.x * _preset.amplitude.x,
|
||||
offset.y * _preset.amplitude.y
|
||||
) * _strength
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://5xuwd0cde3y8
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# CameraShakePreset.gd
|
||||
extends Resource
|
||||
class_name ReedCameraShakePreset
|
||||
|
||||
@export var amplitude := Vector2(6, 6) # 最大位移
|
||||
@export var frequency := 25.0 # 抖动频率
|
||||
@export var fade_in := 0.05
|
||||
@export var hold := 0.1
|
||||
@export var fade_out := 0.15
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://wlqopoksgvjc
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
##TODO:清楚掉這裏和PhantomCamera相關的部分
|
||||
@tool
|
||||
@icon("uid://bsdmq0essfmpk")
|
||||
@icon("res://addons/reedcamera/icon/camera_anchor_icon.svg")
|
||||
class_name CameraAnchor extends Node2D
|
||||
|
||||
const _CONSTANTS = preload("res://addons/reedcamera/_data/CameraSystemConst.gd")
|
||||
|
|
@ -10,6 +10,10 @@ const _CONSTANTS = preload("res://addons/reedcamera/_data/CameraSystemConst.gd")
|
|||
@export var priority: int = 0
|
||||
##此Anchor是否有效
|
||||
@export var enabled: bool = true
|
||||
## =========================
|
||||
## Blend Config
|
||||
## =========================
|
||||
@export_subgroup("Blending")
|
||||
##是否要存在相機過渡時間
|
||||
@export var use_blend: bool = true
|
||||
##過度時間
|
||||
|
|
@ -49,12 +53,6 @@ const _CONSTANTS = preload("res://addons/reedcamera/_data/CameraSystemConst.gd")
|
|||
limit_right = value
|
||||
if Engine.is_editor_hint():
|
||||
queue_redraw()
|
||||
@export_subgroup("Follow")
|
||||
@export var follow_player: bool = false
|
||||
|
||||
|
||||
|
||||
var _camera_global : Node = null
|
||||
|
||||
## 编辑器预览面板设置
|
||||
@export_group("Editor Preview")
|
||||
|
|
@ -66,6 +64,15 @@ var _camera_global : Node = null
|
|||
@export var limit_preview_line_width: float = 2.0
|
||||
|
||||
|
||||
#@export_subgroup("Follow")
|
||||
#@export var follow_player: bool = false
|
||||
|
||||
|
||||
|
||||
var _camera_global : Node = null
|
||||
|
||||
|
||||
|
||||
var _priority: int :
|
||||
set(value):
|
||||
if _priority != value:
|
||||
|
|
@ -147,7 +154,6 @@ func _get_camera_global() -> Object:
|
|||
|
||||
if Engine.has_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME):
|
||||
_camera_global = Engine.get_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME)
|
||||
print("")
|
||||
|
||||
return _camera_global
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
@tool
|
||||
extends Node
|
||||
class_name CameraPointer
|
||||
|
||||
const _CONSTANTS := preload("res://addons/reedcamera/_data/CameraSystemConst.gd")
|
||||
|
||||
var _camera: Camera2D
|
||||
var _editor_valid := false
|
||||
var _runtime_registered := false
|
||||
var _warned := false
|
||||
|
||||
var _final_offset := Vector2.ZERO
|
||||
var _base_position: Vector2
|
||||
|
||||
func _enter_tree() -> void:
|
||||
if Engine.is_editor_hint():
|
||||
call_deferred("_editor_verify")
|
||||
|
||||
func _exit_tree() -> void:
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
_request_unregister()
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
if not _camera:
|
||||
return
|
||||
|
||||
_update_base_position()
|
||||
_update_camera_offset()
|
||||
_apply_camera_transform()
|
||||
|
||||
func _update_base_position():
|
||||
for child in get_children():
|
||||
if child.has_method("get_base_position"):
|
||||
_base_position = child.get_base_position()
|
||||
return
|
||||
|
||||
# fallback
|
||||
_base_position = _camera.global_position
|
||||
|
||||
func _update_camera_offset():
|
||||
var offset := Vector2.ZERO
|
||||
|
||||
for child in get_children():
|
||||
if child.has_method("get_camera_offset"):
|
||||
offset += child.get_camera_offset()
|
||||
|
||||
_final_offset = offset
|
||||
|
||||
func _apply_camera_transform():
|
||||
_camera.global_position = _base_position
|
||||
_camera.offset = _final_offset
|
||||
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if not Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
match what:
|
||||
NOTIFICATION_PARENTED, NOTIFICATION_UNPARENTED:
|
||||
#print("重設parent")
|
||||
call_deferred("_editor_verify")
|
||||
|
||||
## 編輯器層面的通過性驗證
|
||||
func _editor_verify() -> void:
|
||||
_camera = _find_camera()
|
||||
_editor_valid = _camera != null
|
||||
#print(_editor_valid)
|
||||
|
||||
if not _editor_valid:
|
||||
_emit_config_warning()
|
||||
else:
|
||||
_warned = false
|
||||
|
||||
func _ready() -> void:
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
_camera = _find_camera()
|
||||
if not _camera:
|
||||
return
|
||||
|
||||
_request_register()
|
||||
|
||||
func _find_camera() -> Camera2D:
|
||||
var p := get_parent()
|
||||
return p as Camera2D if p is Camera2D else null
|
||||
|
||||
func _request_register() -> void:
|
||||
var sys := Engine.get_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME)
|
||||
if not sys:
|
||||
return
|
||||
|
||||
_runtime_registered = sys.request_register_pointer(self)
|
||||
|
||||
func _request_unregister() -> void:
|
||||
if not _runtime_registered:
|
||||
return
|
||||
|
||||
var sys := Engine.get_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME)
|
||||
if sys:
|
||||
sys.request_unregister_pointer(self)
|
||||
|
||||
_runtime_registered = false
|
||||
|
||||
func _emit_config_warning() -> void:
|
||||
if not Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
if _warned:
|
||||
return
|
||||
|
||||
push_warning(
|
||||
"[CameraPointer] Invalid configuration: parent node must be Camera2D. "
|
||||
+ "Current parent: %s" % (get_parent() if get_parent() else "null")
|
||||
)
|
||||
|
||||
_warned = true
|
||||
|
||||
func get_camera() -> Camera2D:
|
||||
return _camera
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://py4h5jxlncro
|
||||
|
|
@ -5,6 +5,63 @@ const _CONSTANTS = preload("res://addons/reedcamera/_data/CameraSystemConst.gd")
|
|||
|
||||
var _screen_size : Vector2i
|
||||
|
||||
var _camera_points : Array[CameraPointer]
|
||||
var _current_camera_point : CameraPointer
|
||||
|
||||
|
||||
signal anchor_registered(anchor: CameraAnchor)
|
||||
signal anchor_unregistered(anchor: CameraAnchor)
|
||||
|
||||
var _anchors : Array[CameraAnchor]
|
||||
|
||||
#region 相機指針
|
||||
func request_register_pointer(ptr: CameraPointer) -> bool:
|
||||
if not is_instance_valid(ptr):
|
||||
return false
|
||||
|
||||
var cam := ptr.get_camera()
|
||||
if not is_instance_valid(cam):
|
||||
return false # System 决定:无效 camera 不接受注册
|
||||
|
||||
# 去重
|
||||
if ptr in _camera_points:
|
||||
_current_camera_point = ptr
|
||||
return true
|
||||
|
||||
_camera_points.append(ptr)
|
||||
|
||||
# 你可以在这里做选择策略:比如最新优先/priority
|
||||
_current_camera_point = ptr
|
||||
return true
|
||||
|
||||
func request_unregister_pointer(ptr: CameraPointer) -> void:
|
||||
_camera_points.erase(ptr)
|
||||
if _current_camera_point == ptr:
|
||||
_current_camera_point = _camera_points.back() if _camera_points.size() > 0 else null
|
||||
|
||||
func get_current_camera_pointer() -> CameraPointer:
|
||||
return _current_camera_point
|
||||
|
||||
func get_camera() -> Camera2D:
|
||||
return _current_camera_point.get_camera() if _current_camera_point else null
|
||||
#endregion
|
||||
|
||||
#region 相機錨點
|
||||
func register_anchor(anchor: CameraAnchor) -> void:
|
||||
if anchor in _anchors:
|
||||
return
|
||||
_anchors.append(anchor)
|
||||
anchor_registered.emit(anchor)
|
||||
|
||||
func unregister_anchor(anchor: CameraAnchor) -> void:
|
||||
if _anchors.has(anchor):
|
||||
_anchors.erase(anchor)
|
||||
anchor_unregistered.emit(anchor)
|
||||
|
||||
func get_all_anchors() -> Array[CameraAnchor]:
|
||||
return _anchors.duplicate()
|
||||
#endregion
|
||||
|
||||
func _enter_tree() -> void:
|
||||
if not Engine.has_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME):
|
||||
Engine.register_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME, self)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
extends Node
|
||||
class_name ReedCameraAnchorController
|
||||
|
||||
const _CONSTANTS = preload("res://addons/reedcamera/_data/CameraSystemConst.gd")
|
||||
## =========================
|
||||
## Private
|
||||
## =========================
|
||||
var _anchors: Array[CameraAnchor] = []
|
||||
var _current_anchor: CameraAnchor
|
||||
var _current_position := Vector2.ZERO
|
||||
var _tween: Tween
|
||||
|
||||
## =========================
|
||||
## Config
|
||||
## =========================
|
||||
@export var enabled := true
|
||||
@export var move_duration := 0.4
|
||||
@export var ease_type := Tween.EASE_OUT
|
||||
@export var trans_type := Tween.TRANS_CUBIC
|
||||
|
||||
## =========================
|
||||
## Runtime State
|
||||
## =========================
|
||||
|
||||
#var _current_position: Vector2
|
||||
var _target_position: Vector2
|
||||
#var _tween: Tween
|
||||
var _has_target := false
|
||||
|
||||
## =========================
|
||||
## Lifecycle
|
||||
## =========================
|
||||
|
||||
func _ready() -> void:
|
||||
var sys := Engine.get_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME)
|
||||
if not sys:
|
||||
return
|
||||
|
||||
_anchors = sys.get_all_anchors()
|
||||
|
||||
sys.anchor_registered.connect(_on_anchor_added)
|
||||
sys.anchor_unregistered.connect(_on_anchor_removed)
|
||||
|
||||
_evaluate()
|
||||
|
||||
func _on_anchor_added(anchor: CameraAnchor) -> void:
|
||||
_anchors.append(anchor)
|
||||
_evaluate()
|
||||
|
||||
func _on_anchor_removed(anchor: CameraAnchor) -> void:
|
||||
_anchors.erase(anchor)
|
||||
if _current_anchor == anchor:
|
||||
_current_anchor = null
|
||||
_evaluate()
|
||||
|
||||
func _evaluate() -> void:
|
||||
var winner := _pick_best_anchor()
|
||||
if winner == _current_anchor:
|
||||
return
|
||||
|
||||
_switch_to(winner)
|
||||
|
||||
func _pick_best_anchor() -> CameraAnchor:
|
||||
var best: CameraAnchor
|
||||
var best_p := -INF
|
||||
|
||||
for a in _anchors:
|
||||
if not a.enabled:
|
||||
continue
|
||||
if a.priority > best_p:
|
||||
best = a
|
||||
best_p = a.priority
|
||||
|
||||
return best
|
||||
|
||||
func _switch_to(anchor: CameraAnchor) -> void:
|
||||
if not anchor:
|
||||
return
|
||||
|
||||
_current_anchor = anchor
|
||||
var target := anchor.global_position
|
||||
|
||||
if _tween and _tween.is_running():
|
||||
_tween.kill()
|
||||
|
||||
if not anchor.use_blend or anchor.blend_time <= 0.0:
|
||||
_current_position = target
|
||||
return
|
||||
|
||||
_tween = get_tree().create_tween()
|
||||
_tween.set_trans(Tween.TRANS_CUBIC)
|
||||
_tween.set_ease(Tween.EASE_OUT)
|
||||
_tween.tween_property(self, "_current_position", target, anchor.blend_time)
|
||||
|
||||
## =========================
|
||||
## CameraPointer Interface
|
||||
## =========================
|
||||
func get_base_position() -> Vector2:
|
||||
return _current_position
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bhl5it46hv4n2
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
@tool
|
||||
extends Node
|
||||
class_name ReedCameraShakeController
|
||||
|
||||
## =========================
|
||||
## Config
|
||||
## =========================
|
||||
@export var enabled := true
|
||||
|
||||
## =========================
|
||||
## Runtime
|
||||
## =========================
|
||||
|
||||
var _players: Array[ReedCameraShakePlayer] = []
|
||||
var _current_offset := Vector2.ZERO
|
||||
|
||||
func _ready() -> void:
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
set_process(true)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
_players.clear()
|
||||
_current_offset = Vector2.ZERO
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
if not enabled:
|
||||
_current_offset = Vector2.ZERO
|
||||
return
|
||||
|
||||
var offset := Vector2.ZERO
|
||||
|
||||
for p in _players:
|
||||
offset += p.evaluate(delta)
|
||||
|
||||
# 移除已经结束的 player
|
||||
_players = _players.filter(func(p): return p.is_active())
|
||||
|
||||
_current_offset = offset
|
||||
|
||||
## =========================
|
||||
## Public API
|
||||
## =========================
|
||||
func play_shake(preset: ReedCameraShakePreset) -> void:
|
||||
if not preset:
|
||||
return
|
||||
|
||||
var player := ReedCameraShakePlayer.new()
|
||||
player.play(preset)
|
||||
_players.append(player)
|
||||
|
||||
func stop_all() -> void:
|
||||
for p in _players:
|
||||
p.stop()
|
||||
_players.clear()
|
||||
_current_offset = Vector2.ZERO
|
||||
|
||||
## =========================
|
||||
## Pipeline Output
|
||||
## =========================
|
||||
|
||||
func get_camera_offset() -> Vector2:
|
||||
return _current_offset
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dwr1s51svvank
|
||||
|
|
@ -17,16 +17,13 @@ config/icon="res://icon.svg"
|
|||
|
||||
[autoload]
|
||||
|
||||
ReedCameraSystem="*res://addons/reedcamera/scripts/ReedCameraGlobal.gd"
|
||||
CameraSystem="*res://_camera/CameraSystem.tscn"
|
||||
GlobalEvent="*res://_shared/GlobalEvent.gd"
|
||||
ReedVFX="*res://addons/reedfx/vfx/ReedVFXSystem.tscn"
|
||||
ReedSceneRegistry="*res://addons/reedscene/scene/SceneRegistry.gd"
|
||||
ReedCameraSystem="*res://addons/reedcamera/scripts/ReedCameraGlobal.gd"
|
||||
|
||||
[display]
|
||||
|
||||
window/size/viewport_width=640
|
||||
window/size/viewport_height=360
|
||||
window/size/window_width_override=1920
|
||||
window/size/window_height_override=1080
|
||||
window/stretch/mode="canvas_items"
|
||||
|
|
|
|||
Loading…
Reference in New Issue