275 lines
8.9 KiB
GDScript
275 lines
8.9 KiB
GDScript
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
|