xiandie/scene/little_game/书架/书架.gd
2025-06-15 13:11:41 +08:00

275 lines
7.1 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@tool
extends CanvasLayer
signal exiting
signal success
const NON_SELECTED = [-1, -1]
@export var shuffle_times := 20
@export var debug_relocate := false:
set(value):
debug_relocate = false
if Engine.is_editor_hint():
_init_answer_and_connect_signals()
_measure_width_by_row()
for row in range(3):
_relocate_books(row)
@onready var sfx_select = $SfxSelect as Sfx
@onready var sfx_interchange = $SfxInterchange as Sfx
var current_answer := []
var book_width_by_row := []
var suffling := false
# [row, col]
var selected_book := NON_SELECTED:
set(value):
if selected_book == value:
return
# 在 suffling 时不允许改变 selected_book
if suffling:
selected_book = value
return
if selected_book != NON_SELECTED:
_toggle_book(false, selected_book[0], selected_book[1])
if value != NON_SELECTED:
_toggle_book(true, value[0], value[1])
selected_book = value
var gameover = false
func _ready() -> void:
layer = GlobalConfig.CANVAS_LAYER_LITTLE_GAME
# init answer first
_init_answer_and_connect_signals()
if Engine.is_editor_hint():
return
_measure_width_by_row()
# shuffle at the end
_shuffle_books()
func _enter_tree() -> void:
SceneManager.pop_center_notification(tr("ui_press_q_to_exit"))
func _init_answer_and_connect_signals() -> void:
current_answer.clear()
for row in range(3):
var r_size = get_node("./Shelf/Layer" + str(row)).get_child_count()
# current_answer append a r_size arr
var arr = []
for id in range(r_size):
arr.append(id)
var book = _get_book_by_id(row, id)
if not Engine.is_editor_hint():
book.get_node("BookButton").pressed.connect(_on_book_pressed.bind(row, id))
current_answer.append(arr)
func _measure_width_by_row() -> void:
# 书本间的额外间隙,用于调整书本之间的间隔
var extra_gap = [2., 3., 2.]
book_width_by_row = []
for row in range(3):
var length = current_answer[row].size()
var width_arr = []
for col in range(length):
var book_btn = _get_book_by_id(row, col).get_node("BookButton") as TextureButton
width_arr.append(book_btn.texture_normal.get_width() + extra_gap[row])
book_width_by_row.append(width_arr)
func _shuffle_books() -> void:
selected_book = NON_SELECTED
if GlobalConfig.DEBUG:
SceneManager.pop_debug_dialog_info(
"备注", "debug模式每列随机洗牌 1 次,正常模式每列随机洗牌 " + str(shuffle_times) + ""
)
shuffle_times = 1
suffling = true
rand_from_seed(Time.get_ticks_usec())
for row in range(3):
# shuffle each row 20 times
var r_size = current_answer[row].size()
for _i in range(shuffle_times):
var col_1 = randi() % r_size
var col_2 = randi() % r_size
selected_book = [row, col_1]
_interchange_book(row, col_2, false)
_relocate_books(row)
# turn off initilazing after shuffle
suffling = false
func _on_book_pressed(row: int, id: int) -> void:
if gameover:
return
var col = current_answer[row].find(id)
if selected_book == NON_SELECTED:
selected_book = [row, col]
else:
if selected_book == [row, col]:
selected_book = NON_SELECTED
elif selected_book[0] == row:
_interchange_book(row, col)
else:
selected_book = [row, col]
func _get_book_by_id(row: int, id: int) -> Node2D:
return get_node("./Shelf/Layer" + str(row) + "/Book" + str(id))
# func _get_book_by_pos(row: int, col: int) -> Node2D:
# var layer = get_node("./Shelf/Layer" + str(row))
# return layer.get_child(col)
var mute_toggle = false
func _toggle_book(selected: bool, row: int, col: int) -> void:
var id = current_answer[row][col]
var book = _get_book_by_id(row, id)
var book_tween = create_tween()
if not mute_toggle:
sfx_select.play()
if selected:
book_tween.parallel().tween_property(book, "position:y", -10.0, 0.2)
else:
book_tween.parallel().tween_property(book, "position:y", 0.0, 0.2)
func _interchange_book(row: int, col: int, relocate := true) -> void:
if selected_book == NON_SELECTED or selected_book[0] != row:
return
var col2 = selected_book[1]
sfx_interchange.play()
# interchange current_answer
var temp = current_answer[row][col]
current_answer[row][col] = current_answer[row][col2]
current_answer[row][col2] = temp
# reset selected_book
mute_toggle = true
selected_book = NON_SELECTED
mute_toggle = false
# relocate after reset selected_book
if relocate:
_relocate_books(row)
# check answer
if relocate:
_check_answer()
func _relocate_books(row: int) -> void:
selected_book = NON_SELECTED
var r_size = current_answer[row].size()
var x = 0
for col in range(r_size):
var id = current_answer[row][col]
var book = _get_book_by_id(row, id)
book.position.x = x
book.position.y = 0.0
x += book_width_by_row[row][id]
func _check_answer() -> void:
# 第一行需要顺序排列
var row1 = current_answer[0]
for col in range(row1.size()):
if row1[col] != col:
return
# 第二行需要正序排列
var row2 = current_answer[1]
var size2 = row2.size()
if row2[0] == 0:
# 正序
for col in range(1, size2):
if row2[col] != col:
return
else:
return
# # 倒序
# for col in range(size2):
# if row2[col] != size2 - 1 - col:
# return
# 第三行正序或者倒序都可以
var _row3 = current_answer[2]
var _size3 = _row3.size()
if _row3[0] == 0:
# 正序
for col in range(1, _size3):
if _row3[col] != col:
return
else:
# 倒序
for col in range(_size3):
if _row3[col] != _size3 - 1 - col:
return
# # 最后一行按色块排列0-6 蓝色7个在一起7-11 红色5个在一起12-17 黄色6个在一起
# var row3 = current_answer[2]
# # 0: blue, 1: red, 2: yellow
# var visited = [7, 5, 6]
# var visiting_init = true
# var visiting = -1
# for col in range(row3.size()):
# var color = _get_color(row3[col])
# if visiting_init:
# visiting = color
# visiting_init = false
# if color != visiting:
# return
# visited[color] -= 1
# if visited[color] == 0:
# visiting_init = true
# success
_success()
# 0: blue, 1: red, 2: yellow
func _get_color(index: int) -> int:
# 0-6 蓝色7个在一起7-11 红色5个在一起12-17 黄色6个在一起
if index < 7:
return 0
elif index < 12:
return 1
else:
return 2
func _success() -> void:
gameover = true
# 生死簿倒下的动画
$"Shelf/Layer0/Book17/BookButton".hide()
$"Shelf/生死簿".show()
$"Shelf/生死簿".play("书架倒下")
$"Shelf/生死簿/Button".pressed.connect(_on_target_book_pressed, CONNECT_ONE_SHOT)
$"Sfx书本掉落".play()
func _on_target_book_pressed():
$"Shelf/生死簿".play("书架扶正")
await get_tree().create_timer(1.5).timeout
$"生死簿".show()
# 完成后释放信号
$"生死簿".finished.connect(_on_success_finished)
$"Sfx扶正书本".play()
# 生死簿阅读完成后
func _on_success_finished() -> void:
# exit
# exiting.emit()
success.emit()
get_parent().remove_child(self)
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("cancel"):
if not gameover:
get_viewport().set_input_as_handled()
exiting.emit()
get_parent().remove_child(self)
elif event.is_action_pressed("interact"):
# 阻塞交互输入
get_viewport().set_input_as_handled()