第三者が公開されているアドオンで「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 ----#
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.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)
#---- message_box_styler.gd ここまで ----#呼び出す側のスクリプトに @onready と show_message() を書いていきます
show_message の前に set_box_style("title") を書くことでタイトル画面で使えるような、画面中央で大きめのメッセージボックスを出せるようにしてます
下記はシーン(3dNode)にスクリプトを直接紐付けて呼び出すサンプルです
#---- secene_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"
)
#---- scene_0000.gd ----#以下にスクリーンショットつけます
ボタンを押すと遷移しました

