godot-plateformer/_props/tools/rock.gd

118 lines
2.5 KiB
GDScript3
Raw Normal View History

2025-12-29 14:36:00 +08:00
class_name Rock
extends CharacterBody2D
## ===== 配置 =====
@export var falling_gravity: float = 2000.0
@export var max_fall_speed: float = 3000.0
@export var kill_y: float = 10000000.0
@export var shake_x := 2.0
@export var shake_y := 2.0
@export var step_time := 0.034
@export var binded_rock_texture: Node2D
## ===== 常量 =====
const NO_TARGET_Y: float = 1e20
## ===== 状态 =====
var is_falling: bool = false
var fall_target_y: float = NO_TARGET_Y
## ===== 抖动量 =====
var _shake_tween: Tween
var _shake_origin_pos: Vector2
##岩石开始抖动
func start_shaking() -> void:
var sprite := $Sprite2D
if binded_rock_texture: sprite = binded_rock_texture
if not sprite:
return
# 防止重复启动
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:
var sprite := $Sprite2D
if not sprite:
return
if _shake_tween:
_shake_tween.kill()
_shake_tween = null
# 强制回到原位,防止残留偏移
sprite.position = _shake_origin_pos
## 开始下落(可指定目标)
func start_falling(target_y: float = NO_TARGET_Y) -> void:
is_falling = true
fall_target_y = target_y
velocity = Vector2.ZERO
func _physics_process(delta: float) -> void:
if not is_falling:
return
_update_fall(delta)
func _update_fall(delta: float) -> void:
## 速度积分
velocity.y += falling_gravity * delta
velocity.y = min(velocity.y, max_fall_speed)
## 预测下一帧位置
var next_y: float = global_position.y + velocity.y * delta
## 到达目标 / kill
var limit_y: float = min(fall_target_y, kill_y)
if next_y >= limit_y:
global_position.y = limit_y
_on_fall_finished()
return
move_and_slide()
func _on_fall_finished() -> void:
is_falling = false
queue_free() # 或者变成平台 / 播动画