2025-06-19 06:50:06 +00:00
|
|
|
|
extends Node2D
|
|
|
|
|
|
2025-06-20 11:36:00 +00:00
|
|
|
|
# transfer_mode 意味着检测 portal_key,然后显示
|
|
|
|
|
@export var transfer_mode := true
|
2025-06-19 06:50:06 +00:00
|
|
|
|
# 脚步声周期时间
|
2025-06-20 11:36:00 +00:00
|
|
|
|
@export var footstep_wait_time := 0.5
|
|
|
|
|
# 追击速度
|
|
|
|
|
@export var speed := 50
|
|
|
|
|
# 转身范围,超过这个范围/在这个范围内不 hidden 都会转身
|
|
|
|
|
@export var trun_back_detact_x := 150
|
|
|
|
|
# 抓取范围,优先 catch_front 播放 猪头怪抓盒子猫
|
|
|
|
|
# 其次 catch_nearby 播放 猪头怪抓盒子猫后段
|
|
|
|
|
@export var catch_front_x_range := Vector2(55 - 3, 55 + 3)
|
|
|
|
|
@export var catch_nearby_x_range := Vector2(-10, 55)
|
|
|
|
|
# 观测范围,在观测范围内进入盒子仍旧会被抓
|
|
|
|
|
@export var watching_x := 180
|
|
|
|
|
|
|
|
|
|
# 允许被抓后重开游戏
|
|
|
|
|
var allow_restart_game := true
|
|
|
|
|
|
|
|
|
|
@onready var sfx_footstep = $SfxFootstep as Sfx2D
|
|
|
|
|
@onready var sprite2d = $AnimatedSprite2D as AnimatedSprite2D
|
2025-06-19 06:50:06 +00:00
|
|
|
|
|
2025-06-20 11:36:00 +00:00
|
|
|
|
# 检测到猫钻进盒子的过程
|
|
|
|
|
var cat_hiding_detacted = false
|
|
|
|
|
var footstep_timer := Timer.new()
|
|
|
|
|
var player
|
|
|
|
|
var camera
|
|
|
|
|
var catty_canvas_layer
|
|
|
|
|
|
|
|
|
|
# 运动&检测, 初始为 false
|
|
|
|
|
var move_and_detact = false:
|
|
|
|
|
set(val):
|
|
|
|
|
move_and_detact = val
|
|
|
|
|
toggle_footstep_sfx(move_and_detact)
|
|
|
|
|
if val and is_node_ready():
|
|
|
|
|
sprite2d.play("猪头怪走路")
|
|
|
|
|
# 启用的瞬间先执行检测
|
|
|
|
|
_physics_process(0.0)
|
2025-06-19 06:50:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _ready() -> void:
|
2025-06-20 11:36:00 +00:00
|
|
|
|
SceneManager.get_ground().ready.connect(_on_ground_ready)
|
|
|
|
|
# 抓盒子猫后,传送回初始场景,跳过其 intro 过程(从纸面逐渐进入黑板粉笔空间)
|
|
|
|
|
ArchiveManager.archive.set_global_entry("c02_boxcat_skip_intro", true)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _on_ground_ready():
|
|
|
|
|
player = SceneManager.get_player()
|
|
|
|
|
camera = SceneManager.get_camera_marker()
|
|
|
|
|
catty_canvas_layer = SceneManager.get_ground().get_node("盒子猫CanvasLayer")
|
|
|
|
|
var archive = ArchiveManager.archive as AssembledArchive
|
|
|
|
|
var portal = archive.entrance_portal
|
|
|
|
|
var chasing_started = ArchiveManager.get_global_value("c02_boxcat_chasing_started", false)
|
|
|
|
|
if archive.current_scene == "c02_s13":
|
|
|
|
|
# 开始追逐后,禁用二楼两只
|
|
|
|
|
if chasing_started and not transfer_mode:
|
|
|
|
|
queue_free()
|
|
|
|
|
return
|
|
|
|
|
elif not chasing_started:
|
|
|
|
|
if transfer_mode:
|
|
|
|
|
queue_free()
|
|
|
|
|
return
|
|
|
|
|
if portal == "left" and name != &"追猫猪头怪_左侧":
|
|
|
|
|
queue_free()
|
|
|
|
|
return
|
|
|
|
|
if portal != "left" and name != &"追猫猪头怪_右侧":
|
|
|
|
|
queue_free()
|
|
|
|
|
return
|
|
|
|
|
# c02_s13 开始追逐; call_deferred 延时设置
|
|
|
|
|
ArchiveManager.archive.set_global_entry.call_deferred(
|
|
|
|
|
"c02_boxcat_chasing_started", true
|
|
|
|
|
)
|
|
|
|
|
elif not chasing_started:
|
|
|
|
|
# 如果没有开始追逐,且不是 13 号场景(二楼),则销毁
|
|
|
|
|
queue_free()
|
|
|
|
|
return
|
|
|
|
|
# TODO 高度对齐
|
2025-06-19 06:50:06 +00:00
|
|
|
|
position.y = player.position.y
|
|
|
|
|
# 脚步声 timer
|
2025-06-20 11:36:00 +00:00
|
|
|
|
footstep_timer.one_shot = false
|
2025-06-19 06:50:06 +00:00
|
|
|
|
footstep_timer.autostart = false
|
|
|
|
|
footstep_timer.wait_time = footstep_wait_time
|
|
|
|
|
footstep_timer.timeout.connect(_on_footstep_timer_timeout)
|
2025-06-20 11:36:00 +00:00
|
|
|
|
add_child(footstep_timer)
|
|
|
|
|
if transfer_mode:
|
|
|
|
|
visible = false
|
|
|
|
|
var portal_node = (
|
|
|
|
|
SceneManager.get_ground().get_node("DeployLayer/portal_" + portal) as Portal2D
|
|
|
|
|
)
|
|
|
|
|
global_position.x = portal_node.global_position.x
|
|
|
|
|
# 禁用传送过来的 portal 3s
|
|
|
|
|
_disable_portal_a_few_seconds(portal_node)
|
|
|
|
|
# 3 秒后传送
|
|
|
|
|
get_tree().create_timer(1.0).timeout.connect(_do_transfer)
|
|
|
|
|
if GlobalConfig.DEBUG:
|
|
|
|
|
print("猪头怪 Transfer to: " + portal)
|
|
|
|
|
else:
|
|
|
|
|
move_and_detact = true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var footstep_count := 0
|
2025-06-19 06:50:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _on_footstep_timer_timeout() -> void:
|
|
|
|
|
sfx_footstep.play()
|
2025-06-20 11:36:00 +00:00
|
|
|
|
footstep_count += 1
|
|
|
|
|
if footstep_count % 2 == 0:
|
|
|
|
|
# shake camera
|
|
|
|
|
camera.shake_camera(4.0, 5.0)
|
2025-06-19 06:50:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 启用/禁用脚步声
|
|
|
|
|
func toggle_footstep_sfx(play := true):
|
|
|
|
|
if play:
|
|
|
|
|
footstep_timer.start()
|
|
|
|
|
else:
|
|
|
|
|
footstep_timer.stop()
|
|
|
|
|
|
2025-06-19 08:00:59 +00:00
|
|
|
|
|
2025-06-20 11:36:00 +00:00
|
|
|
|
# 禁用传送过来的 portal 3s
|
|
|
|
|
func _disable_portal_a_few_seconds(portal_node: Portal2D):
|
|
|
|
|
portal_node.enabled = false
|
|
|
|
|
await create_tween().tween_interval(3.0).finished
|
|
|
|
|
portal_node.enabled = true
|
2025-06-19 06:50:06 +00:00
|
|
|
|
|
|
|
|
|
|
2025-06-20 11:36:00 +00:00
|
|
|
|
func _do_transfer():
|
|
|
|
|
if player.global_position.x > global_position.x:
|
|
|
|
|
_toggle_flip_h()
|
|
|
|
|
modulate.a = 0.0
|
|
|
|
|
visible = true
|
|
|
|
|
var tween = create_tween()
|
|
|
|
|
tween.tween_property(self, "modulate:a", 1.0, 2.0)
|
|
|
|
|
await tween.finished
|
|
|
|
|
move_and_detact = true
|
2025-06-19 06:50:06 +00:00
|
|
|
|
|
2025-06-19 08:00:59 +00:00
|
|
|
|
|
2025-06-19 06:50:06 +00:00
|
|
|
|
# 转身追击
|
|
|
|
|
func turn_back():
|
2025-06-20 11:36:00 +00:00
|
|
|
|
move_and_detact = false
|
2025-06-19 06:50:06 +00:00
|
|
|
|
# 呼吸一帧,然后转身
|
2025-06-20 11:36:00 +00:00
|
|
|
|
sprite2d.play("猪头怪呼吸")
|
|
|
|
|
await sprite2d.animation_looped
|
|
|
|
|
_toggle_flip_h()
|
|
|
|
|
move_and_detact = true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _toggle_flip_h():
|
|
|
|
|
sprite2d.flip_h = !sprite2d.flip_h
|
|
|
|
|
sprite2d.offset.x = -sprite2d.offset.x
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 抓小猫
|
|
|
|
|
func do_catch(front: bool):
|
|
|
|
|
move_and_detact = false
|
|
|
|
|
SceneManager.freeze_player(0)
|
|
|
|
|
# 抓小猫时 lock palyer
|
|
|
|
|
SceneManager.lock_player()
|
|
|
|
|
# 呼吸一帧,然后抓取
|
|
|
|
|
sprite2d.play("猪头怪呼吸")
|
|
|
|
|
await sprite2d.animation_looped
|
|
|
|
|
player.hide_sprite = true
|
|
|
|
|
if front:
|
|
|
|
|
# 优先 catch_front 播放 猪头怪抓盒子猫
|
|
|
|
|
sprite2d.play("猪头怪抓盒子猫")
|
|
|
|
|
else:
|
|
|
|
|
# 其次 catch_nearby 播放 猪头怪抓盒子猫后段
|
|
|
|
|
sprite2d.play("猪头怪抓盒子猫后段")
|
|
|
|
|
# TODO 音效
|
|
|
|
|
SceneManager.pop_debug_dialog_info("音效", "抓取过程。 从捡小猫开始=" + str(front))
|
|
|
|
|
await sprite2d.animation_finished
|
|
|
|
|
# 等待动画播放后秒,再检查是否允许重开游戏
|
|
|
|
|
if allow_restart_game:
|
|
|
|
|
SceneManager.get_ground_loader().transition_to_scene("c02_s12", "left")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
|
|
|
if not move_and_detact:
|
2025-06-19 08:00:59 +00:00
|
|
|
|
return
|
2025-06-20 11:36:00 +00:00
|
|
|
|
var player_pos = player.global_position
|
2025-06-19 08:00:59 +00:00
|
|
|
|
|
2025-06-20 11:36:00 +00:00
|
|
|
|
# 玩家到猪头怪面前的距离(有符号)
|
|
|
|
|
var signed_x_diff = player_pos.x - global_position.x
|
|
|
|
|
# 默认向左, flip_h 后向右
|
|
|
|
|
if not sprite2d.flip_h:
|
|
|
|
|
signed_x_diff *= -1
|
2025-06-19 08:00:59 +00:00
|
|
|
|
|
2025-06-20 11:36:00 +00:00
|
|
|
|
# 猫是否在盒子里
|
|
|
|
|
var is_cat_hideen = catty_canvas_layer.crawling
|
2025-06-19 08:00:59 +00:00
|
|
|
|
|
2025-06-20 11:36:00 +00:00
|
|
|
|
# 检查隐藏小猫,在观测范围内进入盒子仍旧会被抓
|
|
|
|
|
if signed_x_diff < 0 or signed_x_diff > watching_x:
|
|
|
|
|
# 如果离开一定范围,重置 cat_hiding_detacted
|
|
|
|
|
cat_hiding_detacted = false
|
|
|
|
|
else:
|
|
|
|
|
cat_hiding_detacted = cat_hiding_detacted or not is_cat_hideen
|
2025-06-19 08:00:59 +00:00
|
|
|
|
|
2025-06-20 11:36:00 +00:00
|
|
|
|
# 检查是否抓取
|
|
|
|
|
if cat_hiding_detacted or not is_cat_hideen:
|
|
|
|
|
if signed_x_diff > catch_front_x_range.x and signed_x_diff < catch_front_x_range.y:
|
|
|
|
|
# 优先 catch_front 播放 猪头怪抓盒子猫
|
|
|
|
|
do_catch(true)
|
|
|
|
|
return
|
|
|
|
|
elif signed_x_diff > catch_nearby_x_range.x and signed_x_diff < catch_nearby_x_range.y:
|
|
|
|
|
# 其次 catch_nearby 播放 猪头怪抓盒子猫后段
|
|
|
|
|
do_catch(false)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 检查是否需要转身,超过这个范围/在这个范围内不 hidden 都会转身
|
|
|
|
|
if signed_x_diff < 0 and trun_back_detact_x < -signed_x_diff:
|
|
|
|
|
turn_back()
|
2025-06-19 08:00:59 +00:00
|
|
|
|
return
|
|
|
|
|
|
2025-06-20 11:36:00 +00:00
|
|
|
|
# 更新追击位置
|
|
|
|
|
var mov_delta = speed * delta
|
|
|
|
|
if not sprite2d.flip_h:
|
|
|
|
|
mov_delta *= -1
|
|
|
|
|
global_position.x += mov_delta
|