godot-plateformer/_props/vine_platform/vine_platform.gd

177 lines
4.0 KiB
GDScript3
Raw Normal View History

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
2026-01-24 21:14:38 +08:00
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)
2026-01-24 21:14:38 +08:00
func stop_shaking() -> void:
if _shake_tween:
_shake_tween.kill()
_shake_tween = null
2026-01-24 21:14:38 +08:00
sprite.position = _shake_origin_pos