xiandie/scene/little_game/拼凑信件.gd

194 lines
5.2 KiB
GDScript3
Raw Normal View History

extends CanvasLayer
signal exiting
signal success
2025-02-10 10:59:19 +00:00
@onready var container = %PartsContainer
@onready var whole = %Whole
@onready var content_rect = %Content
# original: 152
var part_size = 110
var positions = []
# from part 0 to 3, rotated by 0, 90, 180, 270 degrees
var rotations = [0, 0, 0, 0]
var images = []
var game_finished = false
var selected := 0:
set(value):
selected = value
_display_selected()
func _ready() -> void:
2025-03-09 14:01:51 +00:00
layer = GlobalConfig.CANVAS_LAYER_LITTLE_GAME
2025-02-10 10:59:19 +00:00
_setup()
_shuffle()
_display_selected()
2025-02-10 10:59:19 +00:00
content_rect.modulate.a = 0.0
content_rect.visible = true
2025-06-15 05:11:41 +00:00
func _enter_tree() -> void:
SceneManager.pop_center_notification(tr("input_拼凑信件"))
await get_tree().create_timer(4.0).timeout
SceneManager.pop_center_notification(tr("ui_press_q_to_exit"))
2025-02-10 10:59:19 +00:00
func _setup() -> void:
# 保存 whole 中的 4 个 part 的位置,然后从 whole 中移除,添加到 container 中
positions.clear()
images.clear()
for i in range(4):
var part = whole.get_child(0) as TextureButton
part.pressed.connect(_select_part.bind(part))
images.append(part.texture_normal.get_image())
positions.append(part.position)
# 从 whole 中移除,添加到 container 中
whole.remove_child(part)
container.add_child(part)
part.texture_click_mask = BitMap.new()
part.texture_click_mask.create_from_image_alpha(images[i])
_container_replace_children()
func _select_part(part) -> void:
selected = part.get_index()
_display_selected()
func _exchange_parts(a: int, b: int) -> void:
var part_a = container.get_child(a)
var part_b = container.get_child(b)
container.move_child(part_a, b)
container.move_child(part_b, a)
# reassign answer
container.move_child(part_a, b)
2025-02-10 10:59:19 +00:00
_container_replace_children()
func _container_replace_children() -> void:
container.get_child(0).position = Vector2(0, 0)
container.get_child(1).position = Vector2(part_size, 0)
container.get_child(2).position = Vector2(0, part_size)
container.get_child(3).position = Vector2(part_size, part_size)
func _rotate_part(direction := 1) -> void:
var part = container.get_child(selected) as TextureButton
var id = int(str(part.name))
rotations[id] = wrapi(rotations[id] + direction, 0, 4)
images[id].rotate_90(direction)
part.texture_normal = ImageTexture.create_from_image(images[id])
2025-02-10 10:59:19 +00:00
part.texture_click_mask.create_from_image_alpha(images[id])
func _shuffle() -> void:
# shuffle answer
for i in range(30):
var a = randi() % 4
var b = randi() % 4
_exchange_parts(a, b)
# shuffle rotations
for i in range(4):
selected = i
for j in range(randi() % 4):
_rotate_part()
selected = 0
func _display_selected() -> void:
if game_finished:
2025-02-10 10:59:19 +00:00
return
for i in range(4):
if i == selected:
container.get_child(i).modulate = Color(1, 1, 1)
else:
container.get_child(i).modulate = Color(0.7, 0.7, 0.7)
func _check_answer() -> void:
2025-02-10 10:59:19 +00:00
var _success = true
for i in range(4):
var part = container.get_child(i)
var id = int(str(part.name))
if rotations[id] != 0 or id != i:
2025-02-10 10:59:19 +00:00
_success = false
break
game_finished = _success
2025-02-10 10:59:19 +00:00
if _success:
# 从 container 中移除,添加到 whole 中
var tween = create_tween()
tween.tween_property(whole, "scale", Vector2.ONE, 1.0)
var diff = whole.position - container.position
whole.position = container.position
for i in range(4):
var part = container.get_child(0)
container.remove_child(part)
whole.add_child(part)
# 逐个恢复到原始 modulate
part.modulate = Color(1, 1, 1)
# 逐个移动到正确位置
tween.parallel().tween_property(part, "position", diff + positions[i], 1.0)
tween.tween_callback(_post_success)
func _post_success():
2025-03-12 07:53:12 +00:00
# 不显示文本,让玩家在重要物品栏去看(提示)
# var tween = create_tween()
# tween.tween_property(content_rect, "modulate:a", 1.0, 1.0)
2025-03-21 13:45:41 +00:00
var texture = preload("res://asset/art/prop/c01/院长的信.png")
var inspector = SceneManager.get_inspector()
2025-06-15 05:11:41 +00:00
inspector.pop_standard_inspection(texture, null, tr("prop_院长的信_说明"), false, true)
2025-03-12 07:53:12 +00:00
SceneManager.enable_important_item("prop_院长的信")
2025-05-30 11:05:06 +00:00
whole.visible = false
2025-03-12 07:53:12 +00:00
# 1s 后退出
await get_tree().create_timer(1.0).timeout
if get_parent() != null:
success.emit()
get_parent().remove_child(self)
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("escape") or event.is_action_pressed("bag"):
return
# block all input except "escape" or "bag"
get_viewport().set_input_as_handled()
if event.is_action_pressed("cancel"):
if game_finished:
success.emit()
else:
exiting.emit()
get_parent().remove_child(self)
return
if game_finished:
2025-02-10 10:59:19 +00:00
return
var handled = false
if event.is_action_pressed("up"):
if selected > 1:
_exchange_parts(selected, selected - 2)
selected -= 2
handled = true
elif event.is_action_pressed("down"):
if selected < 2:
_exchange_parts(selected, selected + 2)
selected += 2
handled = true
elif event.is_action_pressed("left"):
if selected % 2 == 1:
_exchange_parts(selected, selected - 1)
selected -= 1
handled = true
elif event.is_action_pressed("right"):
if selected % 2 == 0:
_exchange_parts(selected, selected + 1)
selected += 1
handled = true
elif event.is_action_pressed("interact"):
_rotate_part()
handled = true
if handled:
2025-02-10 10:59:19 +00:00
$SfxMove.play()
_display_selected()
2025-03-12 07:53:12 +00:00
_check_answer()