xiandie/scene/ground/script/c02/追猫猪头怪.gd

220 lines
6.4 KiB
GDScript3
Raw Normal View History

extends Node2D
# transfer_mode 意味着检测 portal_key然后显示
@export var transfer_mode := true
# 脚步声周期时间
@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
# 检测到猫钻进盒子的过程
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)
func _ready() -> void:
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 高度对齐
position.y = player.position.y
# 脚步声 timer
footstep_timer.one_shot = false
footstep_timer.autostart = false
footstep_timer.wait_time = footstep_wait_time
footstep_timer.timeout.connect(_on_footstep_timer_timeout)
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
func _on_footstep_timer_timeout() -> void:
sfx_footstep.play()
footstep_count += 1
if footstep_count % 2 == 0:
# shake camera
camera.shake_camera(4.0, 5.0)
# 启用/禁用脚步声
func toggle_footstep_sfx(play := true):
if play:
footstep_timer.start()
else:
footstep_timer.stop()
# 禁用传送过来的 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
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
# 转身追击
func turn_back():
move_and_detact = false
# 呼吸一帧,然后转身
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:
return
var player_pos = player.global_position
# 玩家到猪头怪面前的距离(有符号)
var signed_x_diff = player_pos.x - global_position.x
# 默认向左, flip_h 后向右
if not sprite2d.flip_h:
signed_x_diff *= -1
# 猫是否在盒子里
var is_cat_hideen = catty_canvas_layer.crawling
# 检查隐藏小猫,在观测范围内进入盒子仍旧会被抓
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
# 检查是否抓取
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()
return
# 更新追击位置
var mov_delta = speed * delta
if not sprite2d.flip_h:
mov_delta *= -1
global_position.x += mov_delta