xiandie/scene/ground/script/c03/胖子游戏棺材怪.gd
2025-08-05 00:01:54 +08:00

173 lines
5.1 KiB
GDScript

extends AnimatedSprite2D
signal before_restart
var MOVE_SPEED := 180.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 Sfx2D
@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 left_hand_x_offset: float
var right_hand_x_offset: float
var chopped_safe_period := false
var finished := false
func _ready() -> void:
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()
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
_checkout_hand_animation(false)
var tween = create_tween()
if aiming_duration > 0.0:
tween.tween_property(remote_left_shadow, "scale", Vector2.ONE, aiming_duration)
tween.tween_callback(left_side_sprite.play)
tween.tween_property(remote_left_side, "position:y", 0.0, 0.2)
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.ZERO, 0.4)
tween.parallel().tween_property(remote_left_side, "position:y", RESET_Y, 0.5)
tween.tween_callback(toggle_safe_period.bind(false))
func chop_right(aiming_duration := AIMING_DURATION) -> void:
if aiming:
return
hand_mode = 1
aiming += 1
_checkout_hand_animation(false)
var tween = create_tween()
if aiming_duration > 0.0:
tween.tween_property(remote_right_shadow, "scale", Vector2.ONE, aiming_duration)
tween.tween_callback(right_side_sprite.play)
tween.tween_property(remote_right_side, "position:y", 0.0, 0.2)
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.ZERO, 0.4)
tween.parallel().tween_property(remote_right_side, "position:y", RESET_Y, 0.5)
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:
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:
stop()
if footstep_sfx.playing:
footstep_sfx.stop()
else:
var speed = MOVE_SPEED
# 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()
func _checkout_hand_animation(is_move := true) -> void:
var target_animation = ""
if is_move:
target_animation = "棺材怪移动" if hand_mode == 0 else "棺材怪移动右"
else:
target_animation = "棺材怪左砍" if hand_mode == 0 else "棺材怪右砍"
if not is_playing() or animation != target_animation:
if hand_mode == 0:
play(target_animation)
else:
play(target_animation)