ゲームエンジンGodot4.0で3Dスマホゲームを作りたいと思いますが、その前にお勉強しています。
2023/3/1にstable版がリリースされました。
Godot_v4.0-stable_win64.exe.zipを使用しています。
目的
ゲームシステムをつくっていきます。
設定仮面をつくりましょう。ポップアップダイアログで表示/消去するまでです。
設定画面について
設定画面はタイトルと同じように新規にシーンを作成して、global.gd経由で切り替えることもできますが、PopupPanelという機能を使用して表示しましょう。
2023/3/1リリースのGodot4.0 stable版はPopupPanelにいくつか問題がありそうです。
以下の記事では2つ問題がありつつも実装をすすめていますが、不安な方は別の方法(Window/Popup/PopupPanelを使用しない方法)で実装した方がよいと思います。
ベースプロジェクト
下記で作成したプロジェクトをベースに機能追加をします。
【Godot 4.0】スマホ3Dゲームを作るための勉強 その20 ゲームシステムを作る その5 タイトルシーンを作って、神様スクリプトからタイトルシーンとプレイシーンを入れ替えるようにする
https://qiita.com/FootInGlow/items/08a31719f0077d09d4eb
github(Godotのプロジェクトマネージャーからインポートして利用できます)
https://github.com/footinglow/Godot4/tree/main/02_study/S20_GameSystem_005
設定ダイアログを作成します。
プレイヤーがBulletを発射するタイミングは固定で1秒ですが、その間隔を0.1秒~1.0秒の間で設定できるようにします。
新規シーンを作成します。
シーンメニューから新規シーンを作成します。「その他のノード」ボタンを押下します。
「PopupPanel」を追加します。
名称を「SettingsPopupPanel」に変更して、保存します。
「res://settings_popup_panel.tscn」として保存されました。
設定パネルのサイズを決めるControlを追加します。
この後追加するボタンなどのコントロールの親となるControlノードを追加します。
このControlのサイズがPopupPanel全体のサイズになります。
「SettingsPopupPanel」を右クリックして、「Contorl」ノードを追加します。
名称を「ControlBaseSize」に変更します。
「ControlBaseSize」を選択した状態で、インスペクタのControl/Custom Minimum Sizeのx=300px、y=200pxを設定します。
コントロールを配置します。
コントロール3つ表示することにします。
コントロール | 用途 |
---|---|
Label | 「発射間隔1秒」のように現在の設定値をテキスト表示する |
HSlider | スライダーで発射間隔を0.1秒から1.0秒まで0.1秒刻みで調整できるようにします。その結果はLabelに表示します |
Button | 設定完了時に押下します |
Godotのコントロールの配置はコンテナというのを利用して、Controlパーツを縦/横に並べるように配置していきます。
今回は縦に3つ並べたいので、VBoxContainerを使用します(横に並べる場合はHBoxContainerを使用します)
「ControlBaseSize」を右クリックして子ノードを追加から「VBoxContainer」を追加します。
「VBoxContainer」を右クリックして子ノードを追加から下記の3つのコントロールを追加して各種設定をします。
- Label
インスペクタのLabel/Textに「発射間隔1秒」と設定します。
あとでスクリプトから文字列を設定しますが、位置・サイズを見たいので設定します。 - HSlider
- Button
インスペクタのLabel/Textに「設定完了」と設定します。
上部の2Dをクリックすると表示イメージを確認することができます。
表示イメージが表示されない場合、「SettingsPopupPanel」を選択した状態で、インスペクタのWindow/FlagsのVisibleをオンにします。
タイトル画面から設定画面を呼び出すように修正します。
タイトル画面に「設定」ボタンを追加します。
res://title.tscnを開きます。
Titleを右クリックして、子ノードを追加から「Button」を追加します。
名称を「SettingsButton」に変更します。
インスペクタのButton/Textに「設定」と入力します。
シーン内でSettingsButtonをドラッグしてButtonの下に移動しましょう。
「設定」ボタンと「Game Start!」ボタンの配置を変更します。
画面上部の2Dをクリックします。
SettingsButtonが選択されている状態で、ビューの右のアイコンをクリックして中央下のアイコンをクリックします。
「Game Start!」ボタンの下に「設定」ボタンが移動しました。
「Game Start!」ボタンと「設定」ボタンをマウスでドラッグして横に並べましょう。
画面全体で確認するとこのような感じにしました。
「設定」ボタンを押下するとPopupPanelを表示するようにします。
res://title.tscnを開きます(開いていると思います)。
ファイルシステム内の「res://settings_popup_panel.tscn」をシーン内の「Title」にドラッグアンドドロップして追加します。
追加されました。
ディフォルトでは非表示にしたいので、シーン内のSettingsPopupPanelの右の「目」のアイコンをクリックして、目を閉じたアイコンに変更します。
「設定」ボタンのシグナルを受信する処理を実装します。
シーン内の「SettingsButton」を選択した状態で、インスペクタの横のノード/シグナルをクリックしてください。
BaseButton/pressedシグナルを右クリックして「接続」を実行します。
Titleを選択します。受信側メソッドを確認して、「接続」ボタンを押下します。
res://title.gdに_on_settings_button_pressed()メソッドが追加されました。
res://title.gdを下記のように修正します。
extends Control
func _on_button_pressed():
Global.goto_scene("res://game_system.tscn")
func _on_settings_button_pressed():
$SettingsPopupPanel.open()
「設定」ボタンが押下されたシグナルを受信したときに、SettingsPopupPanelのスクリプト内のopen()メソッドを実行するようにします。
次に、SettingsPopupPanelにスクリプトを追加してopen()メソッドを実装します。
res://settings_popup_panel.tscnを開きます。
シーン内のSettingsPopupPanelを右クリックして、「スクリプトをアタッチ」を実行します。
「作成」ボタンを押下するとファイルが追加されます。
extends PopupPanel
func open():
popup_centered()
実行しましょう。
「設定」ボタンを押下すると、PopupPanelが表示されます。「設定完了」ボタン押下やスライダーの処理は実装していないため、操作はできますが何も起きません。PopupPanelの外をクリックするとPopupPanelの表示が消えるのはPopupPanelの機能です。
ちなみにPopupPanelが開いているときに「Game Start!」ボタンを押下するとゲームが開始してしまいますが、これは後で修正します。
PopupPanelを表示するとタイトルの「MyGame」の「M」が消えてしまいます。2023/3/1リリースのGodot4.0にはまだ問題があります。
スライダーの実装
スライダーを変更すると、発射間隔を変更するようにします。
0.1から1.0まで、0.1刻みで選択できるようにします。
res://settings_popup_panel.tscnを開きます。
HSliderを選択した状態でインスペクタのRangeのMin Valueは0.1、Max Valueは1、Stepは0.1にします。
HSliderを選択した状態でインスペクタの横のノード/シグナルの「drag_ended(value_changed:bool)」を右クリックして、「接続」を実行します。
SettingsPopupPanelを選択して、受信側メソッドを確認後、「接続」ボタンを押下します。
res://settings_popup_panel.gdに_on_h_slider_drag_endedメソッドが追加されるので下記のように修正しましょう。
extends PopupPanel
func open():
popup_centered()
func _on_h_slider_drag_ended(value_changed):
$ControlBaseSize/VBoxContainer/Label.text = "発射間隔 %.1f秒" % $ControlBaseSize/VBoxContainer/HSlider.value
-
func _on_h_slider_drag_ended(value_changed):
スライダーを操作して、離したときに呼ばれます。 -
$ControlBaseSize/VBoxContainer/HSlider.value
スライダーの値はHSlider.valueに格納されています。
0.1~1.0の値が取得できます。 -
"発射間隔 %.1f秒" % $ControlBaseSize/VBoxContainer/HSlider.value
文字列を編集するためのformatです。
スライダーの値は浮動小数点なので、%fで受けています。間にある「.1」により小数点第1位まで表示します。 -
$ControlBaseSize/VBoxContainer/Label.text
Label.textに文字列を設定するとLabelの表示を変更できます。
実行しましょう。
スライダーを操作するとLabel表示が変更します。
「設定完了」ボタンを実装する
「設定完了」ボタン押下でPopupPanelの表示を消すようにします。
res://settings_popup_panel.tscnを開きます。
Buttonを選択した状態でインスペクタの横のノード/シグナルの「BaseButton/pressed()」を右クリックして、「接続」を実行します。
SettingsPopupPanelを選択して、受信側メソッドを確認後、「接続」ボタンを押下します。
res://settings_popup_panel.gdに_on_button_pressedメソッドが追加されました。
res://settings_popup_panel.gdを開いて下記のように実装します。
extends PopupPanel
func open():
popup_centered()
func _on_h_slider_drag_ended(value_changed):
print($ControlBaseSize/VBoxContainer/HSlider.value)
$ControlBaseSize/VBoxContainer/Label.text = "発射間隔 %.1f秒" % $ControlBaseSize/VBoxContainer/HSlider.value
func _on_button_pressed():
hide()
_on_button_pressed()メソッドが呼ばれたときに「hide()」を実行して、PopupPanelの表示を消します。
設定完了ボタンを押下するとPopupPanelが消える様になりました。
PopupPanel表示中に「Game Start!」ボタンを押せないようにする
PopupPanel表示中に背景のボタン(Game Start!ボタン、設定ボタン)を押下できないようにします。
SceneTreeを停止する
res://settings_popup_panel.gdを開きます。
get_tree()でSceneTree(アクティブなシーン全体)を取得してpausedフラグをtrueにすると、シーンが停止します。
子ノードも親シーンに従って停止するので、アクティブなシーン全体が停止します。
func open():
get_tree().paused = true
popup_centered()
PopupPanelが消えるときにSceneTreeを再開する
PopupPanelは設定完了ボタン以外にも背景をクリックすると消えるので、PopupPanelが消えるときに発行されるシグナルを利用して、SceneTreeを再開します。
SettingsPopupPanelを選択した状態でインスペクタの横のノード/シグナルの「Popup/popup_hide()」を右クリックして、「接続」を実行します。
SettingsPopupPanelを選択して、受信側メソッドを確認後、「接続」ボタンを押下します。
res://settings_popup_panel.gdに_on_popup_hideメソッドが追加されるので、下記のように修正します。
func _on_popup_hide():
get_tree().paused = false
res://settings_popup_panel.gd全体は下記のようになりました。
extends PopupPanel
func open():
get_tree().paused = true
popup_centered()
func _on_h_slider_drag_ended(value_changed):
print($ControlBaseSize/VBoxContainer/HSlider.value)
$ControlBaseSize/VBoxContainer/Label.text = "発射間隔 %.1f秒" % $ControlBaseSize/VBoxContainer/HSlider.value
func _on_button_pressed():
hide()
func _on_popup_hide():
get_tree().paused = false
PopupPanelは動けるようにする
SceneTreeを停止してもPopupPanelが動けるようにします。
SettingsPopupPanelノードを選択してインスペクタの一番下にある「Node/Process/Mode」を「Always」に変更します。
実行します。
PopupPanel表示中は背景が停止して、PopupPanelを閉じると背景が動き出すのがわかります。
またPopupPanel表示中に「Game Start!」ボタンを押下してもゲームが開始しなくなりました。
Controlをまとめる
PopupPanelを表示するとタイトルの「MyGame」の「M」が消える問題について試行錯誤したときにルートノードのTitleとLabel、Button、SettingsButtonの間にControlを親ノードとして追加したものが残っていました。
あまり意味はないのですが、その22以降にもあるので作業手順として残しておきます。
res://title.tscnのLabel、Button、SettingsButtonの親Controlを作成します。
Titleを右クリックして、子ノードを追加からControlを追加します。
Label、Button、SettingsButtonをドラッグしてControlの子ノードにします。
Titleの下に移動します。
以上です。