extends AnimatedSprite2D signal before_restart # 在玩家移速基础上增加的速度 var MOVE_PLUS_SPEED := 300.0 const RESET_Y := -300.0 @export var mute := false: set(val): mute = val _on_mute_updated() @export var move_target: Node2D @export_enum("left", "right") var hand_mode := 0 @export var left_side_sprite: AnimatedSprite2D @export var right_side_sprite: AnimatedSprite2D @export var left_area: Area2D @export var right_area: Area2D @export var left_static_collision: CollisionShape2D @export var right_static_collision: CollisionShape2D @onready var footstep_sfx = $"Sfx2D棺材怪脚步声" as Sfx2D @onready var chop_sfx = $"Sfx2D棺材怪切刀" as Sfx @onready var remote_left_side = $"左侧" as RemoteTransform2D @onready var remote_right_side = $"右侧" as RemoteTransform2D @onready var remote_left_shadow = $"左落点" as RemoteTransform2D @onready var remote_right_shadow = $"右落点" as RemoteTransform2D var player: MainPlayer var left_hand_x_offset: float var right_hand_x_offset: float var chopped_safe_period := false var finished := false func _ready() -> void: await SceneManager.ground_ready player = SceneManager.get_player() left_hand_x_offset = remote_left_shadow.position.x right_hand_x_offset = remote_right_shadow.position.x left_area.body_entered.connect(_on_player_chopped) right_area.body_entered.connect(_on_player_chopped) _on_mute_updated() if GlobalConfig.DEBUG: animation_changed.connect(func(): print("animation changed:", animation)) func _on_mute_updated() -> void: if not is_node_ready(): return if mute: footstep_sfx.volume_db = -100 else: footstep_sfx.reset_volumn_to_default() # 停止切肉动作, x 对齐到 move_target func refresh_position() -> void: var target_x = move_target.global_position.x if hand_mode == 0: target_x -= left_hand_x_offset else: target_x -= right_hand_x_offset global_position.x = target_x remote_right_side.position.y = RESET_Y remote_left_side.position.y = RESET_Y remote_left_shadow.scale = Vector2.ZERO remote_right_shadow.scale = Vector2.ZERO var aiming := 0 const AIMING_DURATION := 2.0 func chop_left(aiming_duration := AIMING_DURATION) -> void: if aiming: return hand_mode = 0 aiming += 1 var tween = create_tween() if aiming_duration > 0.0: tween.tween_property(remote_left_shadow, "scale", Vector2.ONE, aiming_duration) tween.tween_callback(_checkout_hand_animation.bind(false)) tween.tween_callback(left_side_sprite.play) tween.tween_property(remote_left_side, "position:y", 0.0, 0.15) if aiming_duration <= 0.0: tween.parallel().tween_property(remote_left_shadow, "scale", Vector2.ONE, 0.3) tween.tween_callback(chop_sfx.play) tween.tween_callback(toggle_safe_period.bind(true)) tween.tween_callback(shake) tween.tween_callback(func(): aiming -= 1) tween.tween_interval(0.1) tween.tween_property(remote_left_shadow, "scale", Vector2(0.2, 0.2), 0.2) tween.parallel().tween_property(remote_left_side, "position:y", RESET_Y, 0.4) tween.tween_callback(toggle_safe_period.bind(false)) func chop_right(aiming_duration := AIMING_DURATION) -> void: if aiming: return hand_mode = 1 aiming += 1 var tween = create_tween() if aiming_duration > 0.0: tween.tween_property(remote_right_shadow, "scale", Vector2.ONE, aiming_duration) tween.tween_callback(_checkout_hand_animation.bind(false)) tween.tween_callback(right_side_sprite.play) tween.tween_property(remote_right_side, "position:y", 0.0, 0.15) if aiming_duration <= 0.0: tween.parallel().tween_property(remote_right_shadow, "scale", Vector2.ONE, 0.3) tween.tween_callback(chop_sfx.play) tween.tween_callback(toggle_safe_period.bind(true)) tween.tween_callback(shake) tween.tween_callback(func(): aiming -= 1) tween.tween_interval(0.1) tween.tween_property(remote_right_shadow, "scale", Vector2(0.2, 0.2), 0.5) tween.parallel().tween_property(remote_right_side, "position:y", RESET_Y, 0.4) tween.tween_callback(toggle_safe_period.bind(false)) func toggle_safe_period(safe: bool) -> void: chopped_safe_period = safe left_static_collision.disabled = not safe right_static_collision.disabled = not safe func shake() -> void: SceneManager.get_camera_marker().shake_camera(6.0) func _on_player_chopped(_body) -> void: if chopped_safe_period: return if finished: return finished = true SceneManager.lock_player() await SceneManager.player_action(7) await Util.wait(1.0) SceneManager.unlock_player() before_restart.emit() # restart get_tree().reload_current_scene() func _physics_process(delta: float) -> void: if not player: return var target_x = move_target.global_position.x if hand_mode == 0: target_x -= left_hand_x_offset else: target_x -= right_hand_x_offset var x = global_position.x if chopped_safe_period or abs(target_x - x) < 0.1: if not playing_chopping_animation: stop() if footstep_sfx.playing: footstep_sfx.stop() else: var speed = MOVE_PLUS_SPEED speed += abs(player.velocity.x) if aiming: speed *= 0.6 global_position.x = move_toward(x, target_x, delta * speed) # if Time.get_ticks_msec() % 100 == 0: # prints(x, target_x) if not footstep_sfx.playing: footstep_sfx.play() _checkout_hand_animation(true) var playing_chopping_animation = false func _checkout_hand_animation(moving: bool) -> void: if playing_chopping_animation: return var target_animation = "" if moving: target_animation = "棺材怪移动" if hand_mode == 0 else "棺材怪移动右" if not is_playing(): play(target_animation) else: playing_chopping_animation = true target_animation = "棺材怪左砍" if hand_mode == 0 else "棺材怪右砍" if GlobalConfig.DEBUG: prints("play chopping animation:", target_animation) play(target_animation) Util.timer(1.0, func(): playing_chopping_animation = false)