D3/Char/Player/Player_Components/hit_stop_component.gd
2025-05-10 23:19:52 +08:00

275 lines
8.9 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends Node
var enemy_list : Array
var player : CharacterBody2D
var after_image_list : Array
# 存储动画状态
var stored_animations := {}
# 震屏相关变量
var main_camera: Camera2D
var shake_camera: Camera2D
var shake_strength := 10.0
var shake_timer: Timer
var shake_duration_timer: Timer # 新增:震屏持续时间计时器
var is_frozen := false
func _ready() -> void:
update_freeze_list()
# 获取相机引用
player = get_tree().get_first_node_in_group("Player")
if player:
main_camera = player.get_node("Cameras/Camera")
shake_camera = player.get_node("Cameras/Camera_Shake")
# 确保两个相机的缩放一致
if main_camera and shake_camera:
shake_camera.zoom = main_camera.zoom
# 确保震屏相机初始状态是禁用的
shake_camera.enabled = false
main_camera.enabled = true
# 设置震屏效果计时器
shake_timer = Timer.new()
add_child(shake_timer)
shake_timer.wait_time = 0.01 # 确保频率够快
shake_timer.connect("timeout", _on_shake_timer_timeout)
# 设置持续时间计时器
shake_duration_timer = Timer.new()
add_child(shake_duration_timer)
shake_duration_timer.one_shot = true
shake_duration_timer.connect("timeout", stop_screen_shake)
func update_freeze_list() -> void:
enemy_list = get_tree().get_nodes_in_group("Enemy")
player = get_tree().get_first_node_in_group("Player")
after_image_list = get_tree().get_nodes_in_group("After_Image")
func freeze() -> void:
is_frozen = true
update_freeze_list()
if player:
freeze_player()
for enemy in enemy_list:
if is_instance_valid(enemy) and not enemy.death:
freeze_enemy(enemy)
for after_image in after_image_list:
if is_instance_valid(after_image):
freeze_after_image(after_image)
start_screen_shake()
func unfreeze() -> void:
is_frozen = false
stop_screen_shake()
if player:
unfreeze_player()
for enemy in enemy_list:
#print(enemy)
if is_instance_valid(enemy) and not enemy.death:
unfreeze_enemy(enemy)
for after_image in after_image_list:
if is_instance_valid(after_image):
unfreeze_after_image(after_image)
## 存储动画状态
# 存储动画的关键信息以便后续恢复
# @param animation_player - 要存储状态的动画播放器
# @param key - 用于标识该动画状态的唯一键值
func store_animation_state(animation_player: AnimationPlayer, key: String) -> void:
# 存储四个关键属性:
# - current_animation: 当前播放的动画名称
# - position: 动画播放到的具体位置,用于精确恢复
# - speed_scale: 动画播放速度,某些情况下可能被修改
# - is_playing: 动画是否在播放,用于区分播放/暂停状态
stored_animations[key] = {
"animation": animation_player.current_animation,
"position": animation_player.current_animation_position,
"speed_scale": animation_player.speed_scale,
"is_playing": animation_player.is_playing()
}
## 恢复动画状态
func restore_animation_state(animation_player: AnimationPlayer, key: String) -> void:
if stored_animations.has(key):
var state = stored_animations[key]
if state.animation != "":
animation_player.play(state.animation)
animation_player.seek(state.position, true) # 添加true参数确保更新
animation_player.set_speed_scale(state.speed_scale)
# 如果原来是暂停状态,恢复后也应该暂停
if not state.is_playing:
animation_player.pause()
stored_animations.erase(key)
## 冻结enemy
# 暂停敌人的物理处理和动画播放
# 重要使用pause而不是stop来暂停动画因为stop会重置动画状态
# @param enemy - 要冻结的敌人节点
func freeze_enemy(enemy: CharacterBody2D) -> void:
if not is_instance_valid(enemy):
return
var state_machine = enemy.get_node_or_null("Enemy_State_Machine")
var body_animation = enemy.get_node_or_null("Body_Animation/AnimationPlayer")
# 暂停状态机的物理处理,防止状态切换和位置更新
if state_machine:
state_machine.set_physics_process(false)
if body_animation:
var key = "enemy_" + str(enemy.get_instance_id()) # 使用实例ID确保键值唯一性
store_animation_state(body_animation, key)
body_animation.pause() # 使用pause保持动画状态
## 冻结Player
# 暂停玩家的输入处理、物理处理和动画播放
# 重要:需要同时处理玩家的身体动画和攻击动画
# @param player - 玩家节点
func freeze_player() -> void:
if not is_instance_valid(player):
return
# 禁用玩家的核心功能
player.can_attack = false
#player.can_dash = false
player.set_can_gameplay_input(false)
var state_machine = player.get_node_or_null("Player_State_Machine")
var body_animation = player.get_node_or_null("Body_Animation/AnimationPlayer")
var attack_animation = player.get_node_or_null("Hit/Player_Attack_Component/AnimationPlayer")
# 暂停状态机更新
if state_machine:
state_machine.set_physics_process(false)
# 分别存储和暂停身体动画和攻击动画
if body_animation:
store_animation_state(body_animation, "player_body")
body_animation.pause()
if attack_animation:
store_animation_state(attack_animation, "player_attack")
attack_animation.pause()
## 冻结after_image
func freeze_after_image(after_image: Node2D) -> void:
if not is_instance_valid(after_image):
return
#AfterImageFreezer.freeze_after_image(after_image)
var animation = after_image.get_node_or_null("AnimationPlayer")
if animation:
var key = "enemy_" + str(after_image.get_instance_id()) # 使用实例ID确保键值唯一性
store_animation_state(animation, key)
animation.pause() # 使用pause保持动画状态
## 解冻enemy
# 恢复敌人的物理处理和动画播放
# 特殊处理如果敌人在Hurt_Begin状态被冻结直接切换到Hurt_Air状态
# @param enemy - 要解冻的敌人节点
func unfreeze_enemy(enemy: CharacterBody2D) -> void:
if not is_instance_valid(enemy):
return
var state_machine = enemy.get_node_or_null("Enemy_State_Machine")
var body_animation = enemy.get_node_or_null("Body_Animation/AnimationPlayer")
if body_animation:
var key = "enemy_" + str(enemy.get_instance_id())
# 特殊状态处理Hurt_Begin是过渡状态需要直接切换到Hurt_Air
if stored_animations.has(key):
var stored_state = stored_animations[key]
if stored_state.animation == "Hurt_Begin" or enemy.freeze:
restore_animation_state(body_animation, key)
if state_machine:
state_machine.set_physics_process(true)
state_machine.change_state("hurt_air")
return
restore_animation_state(body_animation, key)
if state_machine:
state_machine.set_physics_process(true)
## 解冻Player
# 恢复玩家的所有功能和动画状态
# @param player - 玩家节点
func unfreeze_player() -> void:
if not is_instance_valid(player):
return
# 重新启用玩家的核心功能
player.can_attack = true
player.can_dash = true
player.set_can_gameplay_input(true)
var state_machine = player.get_node_or_null("Player_State_Machine")
var body_animation = player.get_node_or_null("Body_Animation/AnimationPlayer")
var attack_animation = player.get_node_or_null("Hit/Player_Attack_Component/AnimationPlayer")
# 恢复状态机更新
if state_machine:
state_machine.set_physics_process(true)
# 分别恢复身体动画和攻击动画
if body_animation:
restore_animation_state(body_animation, "player_body")
if attack_animation:
restore_animation_state(attack_animation, "player_attack")
## 解冻After_image
func unfreeze_after_image(after_image: Node2D) -> void:
if not is_instance_valid(after_image):
return
#AfterImageFreezer.unfreeze_after_image(after_image)
var animation = after_image.get_node_or_null("AnimationPlayer")
if animation:
var key = "enemy_" + str(after_image.get_instance_id())
# 特殊状态处理Hurt_Begin是过渡状态需要直接切换到Hurt_Air
if stored_animations.has(key):
restore_animation_state(animation, key)
func start_screen_shake(strength: float = 10.0) -> void:
if main_camera and shake_camera:
shake_strength = strength
var camera_center = main_camera.get_screen_center_position()
main_camera.enabled = false
shake_camera.enabled = true
shake_camera.global_position = camera_center
shake_camera.offset = Vector2.ZERO
shake_timer.start()
func start_screen_shake_with_duration(duration: float, strength: float = 10.0) -> void:
start_screen_shake(strength)
shake_duration_timer.wait_time = duration
shake_duration_timer.start()
func stop_screen_shake() -> void:
if main_camera and shake_camera:
shake_timer.stop()
shake_duration_timer.stop()
shake_camera.offset = Vector2.ZERO
shake_camera.enabled = false
main_camera.enabled = true
# 震屏效果实现
func _on_shake_timer_timeout() -> void:
if shake_camera and shake_camera.enabled:
# 使用较大的随机范围
var rand_x = randf_range(-shake_strength, shake_strength)
var rand_y = randf_range(-shake_strength, shake_strength)
shake_camera.offset = Vector2(rand_x, rand_y)
# 判断是否正在震屏
func is_shaking() -> bool:
return shake_camera != null and shake_camera.enabled