312 lines
8.2 KiB
GDScript
312 lines
8.2 KiB
GDScript
extends CanvasLayer
|
||
|
||
signal exit(success)
|
||
|
||
@onready var animation_player = $AnimationPlayer as AnimationPlayer
|
||
@onready var pivot = $Pivot as Node2D
|
||
@onready var hand_pivot = $Pivot/HandPivot as Node2D
|
||
@onready var label = %RichTextLabel as RichTextLabel
|
||
@onready var audio_player = %AudioStreamPlayer as AudioStreamPlayer
|
||
|
||
# ogg文件:丢球(drop 地面明显碰撞声)+球碰球(hit 响亮)+细碎滚动声(loop)三个部分
|
||
@onready var sfx_hit = $SfxHit as Sfx
|
||
@onready var sfx_shoot = $SfxShoot as Sfx
|
||
@onready var sfx_dispatch = $SfxDispatch as Sfx
|
||
|
||
|
||
var dialogue_c02 = preload("res://asset/dialogue/c02.dialogue")
|
||
|
||
var balls_scene_dict = {
|
||
0: preload("uid://d0tuv2dtlosfe"),
|
||
1: preload("uid://cv12saxinfoi7"),
|
||
2: preload("uid://dr0rwr0xjgnjw"),
|
||
}
|
||
|
||
|
||
func _ready() -> void:
|
||
layer = GlobalConfig.CANVAS_LAYER_LITTLE_GAME
|
||
hand_pivot.modulate.a = 0
|
||
# 0:默认 1:寻找弹珠(老虎钳可以换弹珠) 2:给出弹珠 3:游戏结束
|
||
if ArchiveManager.get_global_value("c02_ball_game_stage", 0) == 2:
|
||
# checkout_round(2)
|
||
checkout_round(0)
|
||
else:
|
||
intro()
|
||
label.hide()
|
||
|
||
|
||
func intro():
|
||
round_id = -1
|
||
# 关闭所有碰撞
|
||
for i in range(3):
|
||
var balls_name = "Balls" + str(i)
|
||
get_node(balls_name).visible = false
|
||
get_tree().call_group(balls_name, "hide_away")
|
||
pivot.get_child(0).modulate.a = 0
|
||
DialogueManager.show_dialogue_balloon_scene(self, dialogue_c02, "c02_弹珠游戏0")
|
||
await dialogue_ended
|
||
|
||
|
||
func intro_finished():
|
||
SceneManager.disable_prop_item("prop_弹珠")
|
||
# 0:默认 1:寻找弹珠(老虎钳可以换弹珠) 2:给出弹珠 3:游戏结束
|
||
# 放入弹珠,开始游戏
|
||
ArchiveManager.set_global_entry("c02_ball_game_stage", 2)
|
||
var ball = pivot.get_child(0) as RigidBody2D
|
||
ball.angular_velocity = 20
|
||
animation_player.play("give_ball")
|
||
await animation_player.animation_finished
|
||
# 开始弹珠游戏
|
||
checkout_round(0)
|
||
|
||
|
||
var round_ready = false
|
||
var round_id := 0 #-1:intro; 0, 1, 2
|
||
var hit_count = 0
|
||
var shooting = false
|
||
|
||
|
||
func checkout_round(r: int):
|
||
round_id = r
|
||
# 关闭所有碰撞
|
||
for i in range(3):
|
||
var balls_name = "Balls" + str(i)
|
||
get_node(balls_name).visible = false
|
||
get_tree().call_group(balls_name, "hide_away")
|
||
reload_round()
|
||
|
||
|
||
# 重置当前回合 introduce:是否播放回合 dialogue
|
||
func reload_round():
|
||
# 重置参数
|
||
round_ready = false
|
||
hit_count = 0
|
||
hand_pivot.modulate.a = 0
|
||
|
||
# 重新加载 balls
|
||
var balls_name = "Balls" + str(round_id)
|
||
var old_balls = get_node(balls_name)
|
||
remove_child(old_balls)
|
||
old_balls.queue_free()
|
||
var new_balls = balls_scene_dict[round_id].instantiate()
|
||
new_balls.name = balls_name
|
||
add_child(new_balls)
|
||
new_balls.z_index = 2
|
||
get_tree().call_group(balls_name, "hide_away")
|
||
|
||
# 分散 balls
|
||
animation_player.play("dispatch_balls")
|
||
await animation_player.animation_finished
|
||
|
||
# 加载手中的球
|
||
reload_hand_ball()
|
||
wave_hand()
|
||
round_ready = true
|
||
|
||
|
||
func do_dispatch_balls():
|
||
var balls_name = "Balls" + str(round_id)
|
||
get_tree().call_group(balls_name, "dispatch", Vector2(296.0, 102.0))
|
||
sfx_dispatch.play()
|
||
|
||
|
||
func reload_hand_ball() -> void:
|
||
shooting = false
|
||
# 重新加载
|
||
var ball_scene = preload("res://scene/little_game/弹珠游戏/ball.tscn")
|
||
var ball = ball_scene.instantiate()
|
||
ball.is_shooter = true
|
||
var old_ball = pivot.get_node_or_null("Ball")
|
||
if old_ball:
|
||
pivot.remove_child(old_ball)
|
||
old_ball.queue_free()
|
||
pivot.add_child(ball)
|
||
pivot.move_child(ball, 0)
|
||
ball.name = "Ball"
|
||
# ball.rand_id()
|
||
ball.hit_ball.connect(_on_hit_ball)
|
||
ball.hit_ball_callback.connect(_on_hit_ball_callback)
|
||
ball.hit_boundary.connect(_on_hit_boundary)
|
||
|
||
|
||
var wave_tween: Tween
|
||
|
||
|
||
func wave_hand() -> void:
|
||
hand_pivot.visible = true
|
||
if hand_pivot.modulate.a < 1:
|
||
create_tween().tween_property(hand_pivot, "modulate:a", 1.0, 0.5)
|
||
# var hand_ball = pivot.get_child(0)
|
||
# if hand_ball.modulate.a < 1:
|
||
# create_tween().tween_property(hand_ball, "modulate:a", 1.0, 0.5)
|
||
# 转动 pivot
|
||
if wave_tween:
|
||
if not wave_tween.is_running():
|
||
wave_tween.play()
|
||
return
|
||
wave_tween = create_tween()
|
||
var timeout = 2.0
|
||
(
|
||
wave_tween
|
||
. tween_property(hand_pivot, "rotation", 1.0, timeout)
|
||
. set_ease(Tween.EASE_OUT)
|
||
. set_trans(Tween.TRANS_SINE)
|
||
)
|
||
(
|
||
wave_tween
|
||
. tween_property(hand_pivot, "rotation", 0.0, timeout)
|
||
. set_ease(Tween.EASE_IN)
|
||
. set_trans(Tween.TRANS_SINE)
|
||
)
|
||
(
|
||
wave_tween
|
||
. tween_property(hand_pivot, "rotation", -1.0, timeout)
|
||
. set_ease(Tween.EASE_OUT)
|
||
. set_trans(Tween.TRANS_SINE)
|
||
)
|
||
(
|
||
wave_tween
|
||
. tween_property(hand_pivot, "rotation", 0.0, timeout)
|
||
. set_ease(Tween.EASE_IN)
|
||
. set_trans(Tween.TRANS_SINE)
|
||
)
|
||
wave_tween.set_loops(9999999)
|
||
|
||
|
||
# interact(E) 与 spacebar 都可以 shoot
|
||
func shoot() -> void:
|
||
if not round_ready or shooting or round_id < 0:
|
||
return
|
||
shooting = true
|
||
sfx_shoot.play()
|
||
# 触发射击事件
|
||
if wave_tween and wave_tween.is_running():
|
||
wave_tween.pause()
|
||
var ball = pivot.get_child(0) as RigidBody2D
|
||
var direction = Vector2(0, -1).rotated(hand_pivot.rotation)
|
||
ball.linear_velocity = direction * 200
|
||
ball.angular_velocity = 20.0
|
||
create_tween().tween_property(hand_pivot, "modulate:a", 0.0, 0.5)
|
||
|
||
|
||
func _on_hit_ball():
|
||
sfx_hit.play()
|
||
sfx_shoot.stop()
|
||
|
||
|
||
func _on_hit_ball_callback():
|
||
reload_hand_ball()
|
||
hit_count += 1
|
||
if round_id == 0:
|
||
round_ready = false
|
||
_success_dialogue()
|
||
await dialogue_ended
|
||
checkout_round(1)
|
||
elif round_id == 1 and hit_count >= 3:
|
||
round_ready = false
|
||
_success_dialogue()
|
||
await dialogue_ended
|
||
checkout_round(2)
|
||
elif round_id == 2 and hit_count >= 5:
|
||
round_ready = false
|
||
game_win()
|
||
else:
|
||
wave_hand()
|
||
shooting = false
|
||
|
||
|
||
func _success_dialogue():
|
||
match round_id:
|
||
0:
|
||
DialogueManager.show_dialogue_balloon_scene(self, dialogue_c02, "c02_弹珠游戏1")
|
||
1:
|
||
DialogueManager.show_dialogue_balloon_scene(self, dialogue_c02, "c02_弹珠游戏2")
|
||
2:
|
||
DialogueManager.show_dialogue_balloon_scene(self, dialogue_c02, "c02_弹珠游戏3")
|
||
|
||
|
||
func _on_hit_boundary():
|
||
sfx_shoot.stop()
|
||
if round_id > 0:
|
||
# 后面的回合必须每次都击中球
|
||
get_tree().call_group("Balls" + str(round_id), "ease_out")
|
||
DialogueManager.show_dialogue_balloon_scene(self, dialogue_c02, "c02_弹珠游戏fail")
|
||
await dialogue_ended
|
||
reload_round()
|
||
else:
|
||
reload_hand_ball()
|
||
wave_hand()
|
||
shooting = false
|
||
|
||
|
||
func game_win() -> void:
|
||
print("game_win 弹珠游戏胜利")
|
||
# 0:默认 1:寻找弹珠(老虎钳可以换弹珠) 2:给出弹珠 3:游戏结束
|
||
ArchiveManager.set_global_entry("c02_ball_game_stage", 3)
|
||
# 弹珠雨
|
||
$BallsFalling.emitting = true
|
||
pivot.visible = false
|
||
DialogueManager.show_dialogue_balloon_scene(self, dialogue_c02, "c02_弹珠游戏4")
|
||
await dialogue_ended
|
||
await get_tree().create_timer(3.0).timeout
|
||
exit.emit(true)
|
||
|
||
|
||
func _unhandled_input(event: InputEvent) -> void:
|
||
if event.is_action_pressed("interact"):
|
||
if round_id == -1:
|
||
# intro 阶段,给出弹珠
|
||
var hud = SceneManager.get_prop_hud() as PropHud
|
||
if SceneManager.get_current_prop(false) != "prop_弹珠":
|
||
hud.on_toggle_invalid_prop()
|
||
else:
|
||
intro_finished()
|
||
else:
|
||
shoot()
|
||
get_viewport().set_input_as_handled()
|
||
elif event.is_action_pressed("space"):
|
||
if round_id >= 0:
|
||
shoot()
|
||
get_viewport().set_input_as_handled()
|
||
|
||
|
||
signal dialogue_ended
|
||
|
||
## The current line
|
||
var dialogue_line: DialogueLine:
|
||
set(value):
|
||
if value:
|
||
dialogue_line = value
|
||
apply_dialogue_line()
|
||
get:
|
||
return dialogue_line
|
||
|
||
|
||
func start(
|
||
dialogue_resource: DialogueResource, title: String, extra_game_states: Array = []
|
||
) -> void:
|
||
var temporary_game_states = [self] + extra_game_states
|
||
self.dialogue_line = await dialogue_resource.get_next_dialogue_line(
|
||
title, temporary_game_states
|
||
)
|
||
|
||
|
||
## Apply any changes to the balloon given a new [DialogueLine].
|
||
func apply_dialogue_line() -> void:
|
||
var translation_key = dialogue_line.translation_key
|
||
label.text = ("[wave amp=10.0 freq=5.0][shake rate=4.0 level=3] " + tr(translation_key))
|
||
label.show()
|
||
# 因为版权问题,有些 mp3 文件打不开,所以使用 ogg 格式
|
||
var audio_path = "res://asset/audio/peiyin/ogg/%s.ogg" % translation_key
|
||
if FileAccess.file_exists(audio_path):
|
||
var stream = load(audio_path)
|
||
audio_player.stream = stream
|
||
audio_player.play()
|
||
await audio_player.finished
|
||
await get_tree().create_timer(1.0).timeout
|
||
else:
|
||
push_warning("No audio file found for " + translation_key)
|
||
await get_tree().create_timer(3.0).timeout
|
||
label.hide()
|
||
dialogue_ended.emit()
|