177 lines
4.0 KiB
GDScript
177 lines
4.0 KiB
GDScript
class_name VinePlatform
|
||
extends StaticBody2D
|
||
|
||
|
||
## ===== 节点引用 =====
|
||
@onready var player_trigger: Area2D = %PlayerTriggerVolumn
|
||
@onready var hook_trigger: Area2D = %HookAttractVolumn
|
||
@onready var sprite: Sprite2D = $Sprite2D
|
||
@onready var collision: CollisionShape2D = $CollisionShape2D
|
||
|
||
|
||
## ===== 配置 =====
|
||
|
||
## 触发到消失的总时间(固定)
|
||
@export var destroy_total_time: float = 2.0
|
||
|
||
## 触发后多久开始抖动(可调)
|
||
@export var shake_start_time: float = 1.0
|
||
|
||
## 消失后多久恢复(再生时间)
|
||
@export var respawn_time: float = 3.0
|
||
|
||
|
||
## 抖动参数
|
||
@export var shake_x: float = 1.0
|
||
@export var shake_y: float = 1.0
|
||
@export var step_time: float = 0.034
|
||
|
||
|
||
## ===== 状态机 =====
|
||
enum State {
|
||
IDLE,
|
||
TRIGGERED,
|
||
DISAPPEARED
|
||
}
|
||
|
||
var _current_state: State = State.IDLE
|
||
|
||
|
||
## ===== 抖动控制 =====
|
||
var _shake_tween: Tween
|
||
var _shake_origin_pos: Vector2
|
||
|
||
## 防止重复触发
|
||
var _sequence_started := false
|
||
|
||
|
||
func _ready() -> void:
|
||
player_trigger.body_entered.connect(_on_player_entered)
|
||
hook_trigger.body_entered.connect(_on_hook_hit)
|
||
|
||
|
||
## ==============================
|
||
## 状态切换
|
||
## ==============================
|
||
func change_state(new_state: State) -> void:
|
||
if new_state == _current_state:
|
||
return
|
||
|
||
_current_state = new_state
|
||
|
||
match new_state:
|
||
State.IDLE:
|
||
_enable_platform(true)
|
||
|
||
State.TRIGGERED:
|
||
_start_destroy_sequence()
|
||
|
||
State.DISAPPEARED:
|
||
_disappear_and_respawn()
|
||
|
||
|
||
## ==============================
|
||
## 触发入口
|
||
## ==============================
|
||
|
||
func _on_player_entered(body: Node) -> void:
|
||
if body is Player:
|
||
_trigger_platform()
|
||
|
||
|
||
func _on_hook_hit(hit_pos: Vector2, hook: Hook) -> void:
|
||
_trigger_platform()
|
||
|
||
|
||
|
||
func _trigger_platform() -> void:
|
||
if _sequence_started:
|
||
return
|
||
_sequence_started = true
|
||
|
||
print("藤蔓平台触发:2秒后消失,再生时间:", respawn_time)
|
||
|
||
change_state(State.TRIGGERED)
|
||
|
||
|
||
## ==============================
|
||
## 销毁流程:抖动 + 消失(非销毁)
|
||
## ==============================
|
||
func _start_destroy_sequence() -> void:
|
||
var shake_time: float = clampf(shake_start_time, 0.0, destroy_total_time)
|
||
var remaining_time: float = destroy_total_time - shake_time
|
||
|
||
# 前半段静止
|
||
if shake_time > 0.0:
|
||
await get_tree().create_timer(shake_time).timeout
|
||
|
||
# 后半段抖动
|
||
if remaining_time > 0.0:
|
||
start_shaking()
|
||
await get_tree().create_timer(remaining_time).timeout
|
||
|
||
stop_shaking()
|
||
|
||
# 进入消失状态
|
||
change_state(State.DISAPPEARED)
|
||
|
||
|
||
## ==============================
|
||
## 消失 + 再生
|
||
## ==============================
|
||
func _disappear_and_respawn() -> void:
|
||
print("平台消失,等待再生...")
|
||
|
||
# 关闭平台
|
||
_enable_platform(false)
|
||
|
||
# 等待再生时间
|
||
await get_tree().create_timer(respawn_time).timeout
|
||
|
||
print("平台恢复!")
|
||
|
||
# 重置触发锁
|
||
_sequence_started = false
|
||
|
||
# 回到初始状态
|
||
change_state(State.IDLE)
|
||
|
||
|
||
## ==============================
|
||
## 启用/禁用平台(关键)
|
||
## ==============================
|
||
func _enable_platform(enable: bool) -> void:
|
||
sprite.visible = enable
|
||
collision.disabled = not enable
|
||
|
||
player_trigger.monitoring = enable
|
||
hook_trigger.monitoring = enable
|
||
|
||
|
||
## ==============================
|
||
## 抖动效果
|
||
## ==============================
|
||
func start_shaking() -> void:
|
||
if _shake_tween and _shake_tween.is_running():
|
||
return
|
||
|
||
_shake_origin_pos = sprite.position
|
||
|
||
_shake_tween = create_tween()
|
||
_shake_tween.set_loops()
|
||
_shake_tween.set_trans(Tween.TRANS_SINE)
|
||
_shake_tween.set_ease(Tween.EASE_IN_OUT)
|
||
|
||
_shake_tween.tween_property(sprite, "position", _shake_origin_pos + Vector2(-shake_x, -shake_y), step_time)
|
||
_shake_tween.tween_property(sprite, "position", _shake_origin_pos + Vector2(shake_x, shake_y), step_time)
|
||
_shake_tween.tween_property(sprite, "position", _shake_origin_pos + Vector2(-shake_x, shake_y), step_time)
|
||
_shake_tween.tween_property(sprite, "position", _shake_origin_pos + Vector2(shake_x, -shake_y), step_time)
|
||
|
||
|
||
func stop_shaking() -> void:
|
||
if _shake_tween:
|
||
_shake_tween.kill()
|
||
_shake_tween = null
|
||
|
||
sprite.position = _shake_origin_pos
|