レベル選択メニュー
この記事は Godot 3から Godot 4 へ内容の書き換え中です。 Godot4では存在しない変数、関数が含まれている場合があります。もしその場合はリポジトリのIssuesまでご報告ください。
課題
ゲームには「レベル選択」メニューが必要となります。ユーザーがグリッド形式のオプションから選べるようにしてください。
解決策
上記の例で示したように、プレイヤーが自由に選択できるレベル「ボックス」で構成されたスクロールグリッドを作成します。まず個々のレベルボックスから始めてください。
1: レベルボックス
以下にノードの設定を示します。
LevelBox: PanelContainer
Label
MarginContainer
TextureRect
TextureRect はロックアイコンの表示用、 Label はレベル番号の表示用に使います。一方が表示されている間は、もう一方は非表示になります。
ご自由にスタイルを設定できます。例としては。
インスペクターで LevelBox のカスタム最小サイズを必ず設定してください。ここでは例として (110, 110) を使用していますが、実際のレイアウト要件に応じて調整が必要となります。
次に、スクリプトを追加し、gui_inputシグナルに接続してください。
@tool
extends PanelContainer
signal level_selected
@export var locked = true:
set = set_locked
@export var level_num = 1:
set = set_level
@onready var lock = $MarginContainer/Lock
@onready var label = $Label
func set_locked(value):
locked = value
if not is_inside_tree():
await ready
lock.visible = value
label.visible = not value
func set_level(value):
level_num = value
if not is_inside_tree():
await ready
label.text = str(level_num)
func _on_gui_input(event):
if locked:
return
if event is InputEventMouseButton and event.pressed:
level_selected.emit(level_num)
print("Clicked level ", level_num)
ここで @tool を使用しているのは、インスペクターでプロパティを変更した場合、その変更が即座に反映されるようにするためです。シーンを実行しなくても変化を確認できます。ぜひお試しください。[ロック] プロパティをクリックして、ロック表示が出たり消えたりするのを確認してください。
本プロジェクトでは実際のレベルを読み込む必要がないため、print() 文を使用してクリックが検出されているかをテストできます。
2: グリッド表示
ボックスシーンが完成したら、次に GridContainer を使用して新規シーンを追加してください。その上に任意の数の LevelBox インスタンスを配置し、列数 値を必ず設定してください。以下は6列に設定した例です。
この例では、テーマオーバーライド / 定数 / H分離幅とV分離幅 がどちらも10に設定されています。
このシーンをLevelGridとして保存します。メニューでは、複数のインスタンスを使用して希望するレベル数を表示します。
3: メニュー画面
これで最終的なメニューを作成できます。
以下が基本レイアウトの概要です。
以下のノードを使用して作成します。
LevelMenu: MarginContainer
VBoxContainer
Title: Label
HBoxContainer
BackButton: TextureButton
ClipControl: Control
NextButton: TextureButton
ノードプロパティを調整:
LevelMenu- テーマオーバーライド/定数/マージン:
20
- テーマオーバーライド/定数/マージン:
VBoxContainer- テーマオーバーライド/定数/間隔:
50
- テーマオーバーライド/定数/間隔:
-
Title- フォントスタイルはお好みでカスタマイズ可能
-
BackButton/NextButton- Ignore Texture Size:
有効化 - Stretch Mode:
中央固定 - Layout/Container Sizing/Horizontal/Expand:
有効化
- Ignore Texture Size:
-
ClipControl- Layout/Clip Contents:
有効化 - Layout/Custom Minimum Size:
(710, 350)(レベルグリッドのサイズに相当)
- Layout/Clip Contents:
ノードClipControl内にグリッドが配置されます。コンテンツを切り取る を有効にすると、コントロール領域を超える内容は自動的に切り取られます。これにより、水平スクロール可能なグリッドセットを作成できるようになります。ClipControlにHBoxContainer 要素をGridBoxという名前で追加し、その内部にインスタンス3個以上の LevelGridを配置してください。
必ずテーマのオーバーライド/定数/区切り文字を 0 に設定してください。
レイアウトはこの例と同様に設定してください(動作を分かりやすくするため、コンテンツの切り取り機能は無効にしています):
「クリップコンテンツ」を有効にすると、3つのグリッドはすべて表示されますが、ClipControlでは1つずつしか表示されないようになっています。
さて、メニューをスクロールするには、GridBox を左右に 710 ピクセル分シフトさせる必要があります。
110 (width of each LevelBox)
* 6 (grid columns)
+ 10 (grid spacing) * 5
== 710
「なぜこの場面でScrollContainerを使わないのか」と疑問に思われるかもしれません。もちろん、使用することはできますが、連続スクロールを望んでいませんし、スクロールバーが表示されることも避けたいからです。
スクリプトを LevelMenu に追加し、2つのボタンの pressedシグナルを接続してください。
extends MarginContainer
var num_grids = 1
var current_grid = 1
var grid_width = 710
@onready var gridbox = $VBoxContainer/HBoxContainer/ClipControl/GridBox
func _ready():
# Number all the level boxes and unlock them
# Replace with your game's level/unlocks/etc.
# You can also connect the "level_selected" signals here
num_grids = gridbox.get_child_count()
for grid in gridbox.get_children():
for box in grid.get_children():
var num = box.get_position_in_parent() + 1 + 18 * grid.get_position_in_parent()
box.level_num = num
box.locked = false
func _on_BackButton_pressed():
if current_grid > 1:
current_grid -= 1
gridbox.rect_position.x += grid_width
func _on_NextButton_pressed():
if current_grid < num_grids:
current_grid += 1
gridbox.rect_position.x -= grid_width
シーンを実行する際は、「次へ」ボタンと「戻る」ボタンをクリックし、期待通りにスクロールされるか確認してください。個々のレベルボックスをクリックするとコンソールに出力が表示されるはずです。
ダウンロード可能なサンプルプロジェクトでは、スクロールアニメーション用のTween機能を含む完全な実装例を確認できます(Tweenを使えば、あらゆる動作がより洗練されたものになります)。
プロジェクトのダウンロード
プロジェクトコードはこちらからダウンロードできます。https://github.com/godotrecipes/ui_level_select