第三者が公開されているアドオンで「Dialogなんとか」がボチボチあるけど、godot のバージョンアップに追随しているかわからなく、そのアドオンの使い方を理解するための学習コストと自作のコストが釣り合わないと感じました
2D 3D 両方で使えるものをざっくり作ります
yes/no のように選択できるボタンも内包します
作成メモを残します
シーン(scene)内に、ツリーを作ります
何とかscene
CanvasLayer
MessageBox ←Control を作って、名前を「MessageBox」にします
Panel
Label
ButtonYes
ButtonNo ←Button を2つ作って、名前を「ButtonYes」「ButtonNo」にします
パラメータは .gd スクリプトで設定するので、ザクザクとツリーを作ります
MessageBox 行の横に紙・スクリプトのアイコンがついていますね
message_box.gd を紐付けて動作させます
大きさや色は message_box_styler.gd で設定します
#---- message_box.gd ----#
# ---- message_box.gd ここまで ----#extends Control @onready var label = $Panel/Label @onready var button_yes = $Panel/ButtonYes @onready var button_no = $Panel/ButtonNo var yes_callback: Callable = func(): pass var no_callback: Callable = func(): pass var _on_buttonYes_pressed: Callable = func(): pass var _on_buttonNo_pressed: Callable = func(): pass # サイズ・色などを直接設定する関数 func set_box_style_custom(box_size: Vector2, box_position: Vector2, bg_color: Color, text_color: Color): $Panel.size = box_size $Panel.position = box_position var style_box := StyleBoxFlat.new() style_box.bg_color = bg_color style_box.corner_radius_all = 8 $Panel.add_theme_stylebox_override("panel", style_box) $Panel/Label.add_theme_color_override("font_color", text_color) # プリセットスタイルを適用する関数 func set_box_style(style: String = "default"): match style: "title": MessageBoxStyler.apply_title_style(self) _: MessageBoxStyler.apply_default_style(self) ###func show_message(text: String, on_yes: Variant = null, on_no: Variant = null): func show_message( text: String, on_yes: Variant = null, on_no: Variant = null, yes_text: String = "Yes", no_text: String = "No" ): if label == null: push_error("x label が null です。ノード 'Panel/Label' を確認してください") else: label.text = text visible = true button_yes.visible = on_yes != null button_no.visible = on_no != null button_yes.text = yes_text button_no.text = no_text yes_callback = on_yes if on_yes != null else func(): pass no_callback = on_no if on_no != null else func(): pass yes_callback = on_yes if on_yes != null else func(): pass no_callback = on_no if on_no != null else func(): pass func _on_button_yes_pressed(): visible = false yes_callback.call() func _on_button_no_pressed(): visible = false no_callback.call() func _ready(): hide() # o シグナルが接続されていない場合に備えて接続 $Panel/ButtonYes.pressed.connect(_on_button_yes_pressed) $Panel/ButtonNo.pressed.connect(_on_button_no_pressed) # デフォルトボタン動作 _on_buttonYes_pressed = func(): pass _on_buttonNo_pressed = func(): pass func _on_ButtonYes_pressed(): _on_buttonYes_pressed.call() func _on_ButtonNo_pressed(): _on_buttonNo_pressed.call() func set_button_texts(text1: String, text2: String): if $ButtonYes and $ButtonNo: $ButtonYes.text = text1 $ButtonNo.text = text2 else: push_error("x ButtonYes または ButtonNo が見つかりません") func set_callbacks(callback1: Callable, callback2: Callable): _on_buttonYes_pressed = callback1 _on_buttonNo_pressed = callback2
#---- message_box_styler.gd ----#
#---- message_box_styler.gd ここまで ----#class_name MessageBoxStyler static func apply_title_style(box: Control): assert(box != null) var panel := box.get_node("Panel") panel.size = Vector2(800, 400) panel.position = Vector2(500, 300) panel.modulate = Color(2, 2, 2, 0.8) var stylebox := StyleBoxFlat.new() stylebox.bg_color = Color(0.1, 0.1, 0.1, 0.6) stylebox.border_width_bottom = 2 stylebox.border_color = Color(1, 1, 0) panel.add_theme_stylebox_override("bg", stylebox) var label := box.get_node("Panel/Label") if label.label_settings == null: label.label_settings = LabelSettings.new() label.label_settings.font_size = 48 label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER var button_yes := box.get_node("Panel/ButtonYes") var button_no := box.get_node("Panel/ButtonNo") button_yes.size = Vector2(400, 50) button_yes.position = Vector2(100, 160) button_yes.text = "Yes" button_no.size = Vector2(400, 50) button_no.position = Vector2(100, 260) button_no.text = "No" button_yes.size_flags_horizontal = 0 button_no.size_flags_horizontal = 0 ###var font_settings := LabelSettings.new() ###font_settings.font_size = 36 # Yes ボタン button_yes.text = "Yes" button_yes.add_theme_font_size_override("font_size", 24) button_yes.add_theme_color_override("font_color", Color(0, 0, 0, 1.0)) # 黒文字 var yes_style := StyleBoxFlat.new() yes_style.bg_color = Color(0.4, 0.9, 0.4, 1.0) # 緑 button_yes.add_theme_stylebox_override("normal", yes_style) # No ボタン button_no.text = "No" button_no.add_theme_font_size_override("font_size", 24) button_no.add_theme_color_override("font_color", Color(0, 0, 0, 1.0)) var no_style := StyleBoxFlat.new() no_style.bg_color = Color(0.9, 0.4, 0.4, 1.0) # 緑 button_no.add_theme_stylebox_override("normal", no_style) print("ButtonNo pos: ", button_no.position) print("ButtonNo size: ", button_no.size) print("Panel size: ", panel.size) # --- パネルが画面外にはみ出ないように調整 --- var screen_size = box.get_viewport().get_visible_rect().size # パネルのサイズが大きすぎたら調整 panel.size.x = min(panel.size.x, screen_size.x - 20) panel.size.y = min(panel.size.y, screen_size.y - 20) # パネルの位置がはみ出していたら調整 if panel.position.x + panel.size.x > screen_size.x: panel.position.x = screen_size.x - panel.size.x - 10 if panel.position.y + panel.size.y > screen_size.y: panel.position.y = screen_size.y - panel.size.y - 10 # 画面外に飛びすぎていたら 0 に制限(逆方向) panel.position.x = max(panel.position.x, 10) panel.position.y = max(panel.position.y, 10) static func apply_default_style(box: Control): assert(box != null) var panel := box.get_node("Panel") panel.size = Vector2(800, 240) panel.position = Vector2(100, 500) panel.modulate = Color(0, 0, 0, 0.8) var stylebox := StyleBoxFlat.new() stylebox.bg_color = Color(0.1, 0.1, 0.1, 0.6) stylebox.border_width_bottom = 2 stylebox.border_color = Color(1, 0, 0) panel.add_theme_stylebox_override("bg", stylebox) var label := box.get_node("Panel/Label") if label.label_settings == null: label.label_settings = LabelSettings.new() label.label_settings.font_size = 24 label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER panel.modulate = Color(1, 1, 1, 1) # ← 透明度の影響を排除 var button_yes := box.get_node("Panel/ButtonYes") var button_no := box.get_node("Panel/ButtonNo") # Yes ボタン button_yes.text = "Yes" button_yes.add_theme_font_size_override("font_size", 24) button_yes.add_theme_color_override("font_color", Color(0, 0, 0, 1.0)) # 黒文字 var yes_style := StyleBoxFlat.new() yes_style.bg_color = Color(0.4, 0.9, 0.4, 1.0) # 緑 button_yes.add_theme_stylebox_override("normal", yes_style) button_yes.position = Vector2(100, 120) # No ボタン button_no.text = "No" button_no.add_theme_font_size_override("font_size", 24) button_no.add_theme_color_override("font_color", Color(0, 0, 0, 1.0)) # 黒文字 var no_style := StyleBoxFlat.new() ###no_style.bg_color = Color(1.0, 0.5, 0.6, 1.0) # ピンク寄り赤 no_style.bg_color = Color(0.4, 0.9, 0.4, 1.0) # 緑 button_no.add_theme_stylebox_override("normal", no_style) button_no.position = Vector2(50, 60) print("ButtonNo pos: ", button_no.position) print("ButtonNo size: ", button_no.size) print("Panel size: ", panel.size) # --- パネルが画面外にはみ出ないように調整 --- var screen_size = box.get_viewport().get_visible_rect().size # パネルのサイズが大きすぎたら調整 panel.size.x = min(panel.size.x, screen_size.x - 20) panel.size.y = min(panel.size.y, screen_size.y - 20) # パネルの位置がはみ出していたら調整 if panel.position.x + panel.size.x > screen_size.x: panel.position.x = screen_size.x - panel.size.x - 10 if panel.position.y + panel.size.y > screen_size.y: panel.position.y = screen_size.y - panel.size.y - 10 # 画面外に飛びすぎていたら 0 に制限(逆方向) panel.position.x = max(panel.position.x, 10) panel.position.y = max(panel.position.y, 10)
呼び出す側のスクリプトに @onready と show_message() を書いていきます
show_message の前に set_box_style("title") を書くことでタイトル画面で使えるような、画面中央で大きめのメッセージボックスを出せるようにしてます
下記はシーン(3dNode)にスクリプトを直接紐付けて呼び出すサンプルです
#---- secene_0000.gd ----#
#---- scene_0000.gd ----#extends Node3D @onready var msgbox = $world/CanvasLayer/MessageBox ###@onready var player = $world/Player # player の取得も必要ならここで func _ready(): msgbox.set_box_style("title") msgbox.show_message("This is GAME. start game?", func(): ###player.enabled = true print("o YES select. move scene") get_tree().change_scene_to_file("res://scene/_scene_0001/scene_0001.tscn"), func(): ###player.enabled = true print("No select..."), "Start Game", "No Game" )
以下にスクリーンショットつけます
ボタンを押すと遷移しました