2020/10/28(水) [n年前の日記]
#1 [godot] Godot Engineでゲームのメインシーンを作成
Godot Enigne 3.2.3 x64 の勉強を兼ねて、Apple Catcher っぽいゲームを作成中。
前回までの作業でプレイヤーシーンと林檎・爆弾の発生シーンを作れたので、今回は、ゲームのメインシーンを作成してみる。
前回までの作業でプレイヤーシーンと林檎・爆弾の発生シーンを作れたので、今回は、ゲームのメインシーンを作成してみる。
◎ ルートノードを作成。 :
新規シーンを作って、ルートノードを作成する。
Godot Engine で2Dゲームを作る場合、「メインシーンのルートノードには Node を使え」という話をどこかで見かけた記憶があるのでソレに従う。
「その他のノード」を選択。
「Node」を選んで「作成」。
ルートノードとして Node が追加された。
分かりやすくするために、ノード名を「Main」に変更。
Godot Engine で2Dゲームを作る場合、「メインシーンのルートノードには Node を使え」という話をどこかで見かけた記憶があるのでソレに従う。
「その他のノード」を選択。
「Node」を選んで「作成」。
ルートノードとして Node が追加された。
分かりやすくするために、ノード名を「Main」に変更。
◎ 子ノードを追加。 :
子ノードとして、プレイヤーキャラのシーンと、林檎や爆弾の発生シーンを追加する。
「シーンファイルをノードとしてインスタンスにします」ボタンをクリック。プラスマークの右にあるボタン。
子にするシーンを選ぶ。プレイヤーキャラのシーン、assets/Player.tscn を選択して「開く」。
同様に、林檎や爆弾の発生シーン、assets/ItemGenerator.tscn も選択して「開く」。
Mainノードの下に、Player と ItemGenerator がぶら下がっている構成にした。
「シーンファイルをノードとしてインスタンスにします」ボタンをクリック。プラスマークの右にあるボタン。
子にするシーンを選ぶ。プレイヤーキャラのシーン、assets/Player.tscn を選択して「開く」。
同様に、林檎や爆弾の発生シーン、assets/ItemGenerator.tscn も選択して「開く」。
Mainノードの下に、Player と ItemGenerator がぶら下がっている構成にした。
◎ シーンを保存。 :
◎ 実行してみる。 :
◎ 衝突判定処理を書く。 :
前述の画面は一見するとゲームっぽい画面だけど、プレイヤー、林檎、爆弾は衝突判定の類をまだ何もしていないので、これでは全然ゲームになってない。そのあたりの処理を追加していく。
プレイヤーキャラは、アタリ範囲を持てるArea2Dノードを使っているけれど。Area2Dノードは、自分のアタリ範囲にRigidBody2D が入ってきた時に、「何かが自分に当たったよ」と教えてくれる、body_entered(body) シグナルを発行することができる。
つまり、Playerノードが持ってるシグナル、body_entered にメソッドを接続してやれば、「プレイヤーに林檎か爆弾が当たった時にメソッドを呼んで何か処理をする」という状態を作れる。
Playerノードを選択して、ノードタブを選択。body_entered(body:Node) を選んで、「接続」。
「メソッドにシグナルを接続」ウインドウが開くので、「Player」を選択して「接続」。受信側メソッド名はそのままでいい。
プレイヤーキャラのスクリプト、Player.gd の最後に、メソッド _on_Player_body_entered(body) が追加された。
このメソッドの中に、林檎や爆弾と当たった時の処理を書けばいい。
スクリプトを書く。
追加する内容は以下。
_Player.gd
body には、林檎か爆弾のどちらかのインスタンスが入ってくるので、それが林檎なのか爆弾なのかを判別しないといけないけれど…。
以前、林檎や爆弾のスクリプトを書いた際に、以下を記述してあるので…。
print("hoge") で、Godot Engine エディタ画面の出力ウインドウにメッセージを出力することができる。
また、林檎と衝突した場合、その林檎はもう不要なので、body.queue_free() を呼んで林檎を消去してやる。
衝突判定処理を書けたので、F6キーを押して実行してみる。
プレイヤーが林檎か爆弾と衝突するたびに、出力ウインドウにどちらに当たったかが出力された。ちゃんと衝突判定が動いている。後はこのメソッドの中で、林檎を取った時の処理や、爆弾に当たった時の処理を書いていけばいい。
プレイヤーキャラは、アタリ範囲を持てるArea2Dノードを使っているけれど。Area2Dノードは、自分のアタリ範囲にRigidBody2D が入ってきた時に、「何かが自分に当たったよ」と教えてくれる、body_entered(body) シグナルを発行することができる。
つまり、Playerノードが持ってるシグナル、body_entered にメソッドを接続してやれば、「プレイヤーに林檎か爆弾が当たった時にメソッドを呼んで何か処理をする」という状態を作れる。
Playerノードを選択して、ノードタブを選択。body_entered(body:Node) を選んで、「接続」。
「メソッドにシグナルを接続」ウインドウが開くので、「Player」を選択して「接続」。受信側メソッド名はそのままでいい。
プレイヤーキャラのスクリプト、Player.gd の最後に、メソッド _on_Player_body_entered(body) が追加された。
このメソッドの中に、林檎や爆弾と当たった時の処理を書けばいい。
スクリプトを書く。
追加する内容は以下。
_Player.gd
func _on_Player_body_entered(body): if body.kind == "Apple": print("Apple") body.queue_free() # kill Apple else: print("bomb")
body には、林檎か爆弾のどちらかのインスタンスが入ってくるので、それが林檎なのか爆弾なのかを判別しないといけないけれど…。
以前、林檎や爆弾のスクリプトを書いた際に、以下を記述してあるので…。
export var kind = "Apple"
export var kind = "bomb"body.kind に "Apple" が入ってるのか、それとも "bomb" が入ってるのかを調べれば、林檎か爆弾なのかを判別できる。 *1
print("hoge") で、Godot Engine エディタ画面の出力ウインドウにメッセージを出力することができる。
また、林檎と衝突した場合、その林檎はもう不要なので、body.queue_free() を呼んで林檎を消去してやる。
衝突判定処理を書けたので、F6キーを押して実行してみる。
プレイヤーが林檎か爆弾と衝突するたびに、出力ウインドウにどちらに当たったかが出力された。ちゃんと衝突判定が動いている。後はこのメソッドの中で、林檎を取った時の処理や、爆弾に当たった時の処理を書いていけばいい。
◎ メインシーンとして設定。 :
今回作った Main.tscn を、このプロジェクトのメインシーンとして設定しておく。ファイル一覧ウインドウ内で、Main.tscn を右クリック。「メインシーンとして設定」を選ぶ。
これで、Godot Enigne を起動してプロジェクトを開いたときに、Main.tscn が開かれた状態になる。
さて、林檎や爆弾と当たる状態にはなったけど、当たった時に何かアクションが欲しい。例えば林檎をキャッチした時はスコアが増えてほしい…。次回はスコア表示等を担当するシーンを作りたい。
これで、Godot Enigne を起動してプロジェクトを開いたときに、Main.tscn が開かれた状態になる。
さて、林檎や爆弾と当たる状態にはなったけど、当たった時に何かアクションが欲しい。例えば林檎をキャッチした時はスコアが増えてほしい…。次回はスコア表示等を担当するシーンを作りたい。
*1: もしかすると、林檎と爆弾に異なる「グループ名」を指定して、グループ名で判別してしまってもいいのかもしれない。
[ ツッコむ ]
#2 [godot] Godot EngineでHUDシーンを作成
Godot Enigne 3.2.3 x64 の勉強を兼ねて、Apple Catcher っぽいゲームを作成中。
今回は、スコア、ゲームタイトル、スタートボタンの表示を担当するシーンを作成してみる。ちなみに、スコア表示などをする部分はHUD(Head-Up Display)と呼ばれているらしい。
今回は、スコア、ゲームタイトル、スタートボタンの表示を担当するシーンを作成してみる。ちなみに、スコア表示などをする部分はHUD(Head-Up Display)と呼ばれているらしい。
◎ HUDシーンを作成。 :
HUDシーンを新規作成。シーン → 新規シーンを選択。
Godot Engine は、スコアやタイトルなどを画面に表示する場合、CanvasLayerノードを使うことになっているらしい。「その他のノード」を選択。
「CanvasLayer」を選んで「作成」。
CanvasLayerノードがルートノードとして追加された。左上のプラスマークをクリックして子ノードを追加していく。
文字列表示を担当する Labelノードを2つ、ボタンを担当する Buttonノードを1つを、CanvasLayerの子ノードとして追加した。
分かりやすいように名前を変更しておく。
シーンを保存。シーン → 名前を付けてシーンを保存、を選択。
res://assets/ の下に、Hud.tscn として保存する。
Godot Engine は、スコアやタイトルなどを画面に表示する場合、CanvasLayerノードを使うことになっているらしい。「その他のノード」を選択。
「CanvasLayer」を選んで「作成」。
CanvasLayerノードがルートノードとして追加された。左上のプラスマークをクリックして子ノードを追加していく。
文字列表示を担当する Labelノードを2つ、ボタンを担当する Buttonノードを1つを、CanvasLayerの子ノードとして追加した。
分かりやすいように名前を変更しておく。
Hud (CanvasLayer) │ ├─ Message (Label) : ゲームタイトルや「GAME OVER」の表示に使う。 │ ├─ Score (Label) : スコア表示を担当。 │ └─ StartButton (Button) : スタートボタンを担当。
シーンを保存。シーン → 名前を付けてシーンを保存、を選択。
res://assets/ の下に、Hud.tscn として保存する。
◎ テキスト内容を指定。 :
Messageノードにゲームタイトル名を表示させる。Messageノードを選択。
Textプロパティに、今回のゲームタイトル「NEWTOTOTONE」を入力。また、Align と Valign を Center にしておく。これで文字列が中央揃えで表示される。
Textプロパティに、今回のゲームタイトル「NEWTOTOTONE」を入力。また、Align と Valign を Center にしておく。これで文字列が中央揃えで表示される。
◎ 表示位置を調整。 :
◎ フォントファイルをプロジェクトにインポート。 :
これで表示文字列の指定とレイアウトはできたけど、文字が小さい。これでは読めない…。
ちゃんとした表示にするためには、フォントファイルが必要になる。Godot Engine はフォントファイルとして ttfファイルやotfファイルが使えるので、入手してインポートすればいい。
しかし、一般的にフォントファイルはライセンスが指定されていて、ものによってはゲームに同梱することが許されてなかったりする。
ここは比較的自由に使えるラインセンスのフォントを入手しないといけないわけだけど…。ありがたいことに、ドットコロンさんがいくつかのフォントファイルをCC0ライセンスで公開してくれているので、感謝しつつ使わせてもらうことにする。マジ助かります…。ありがたや…。
_ドットコロン
_Aileron | ドットコロン
_CC0について ― “いかなる権利も保有しない” | クリエイティブ・コモンズ・ジャパン
_CC0の日本語版が公開されました | 著作権のネタ帳
今回は Aileronフォントを使わせてもらうことにした。ダウンロードして解凍すると、中に otfファイルが入ってるので、今回は以下の2つを利用。
エクスプローラ等からフォントファイルをGodot Engineのエディタ画面にドラッグアンドドロップ。これでフォントファイルがプロジェクトフォルダ内にコピーされる。
res://直下にコピーされてしまった。ドラッグして resourcesフォルダ内に移動。
resourcesフォルダ内に入った。
ちゃんとした表示にするためには、フォントファイルが必要になる。Godot Engine はフォントファイルとして ttfファイルやotfファイルが使えるので、入手してインポートすればいい。
しかし、一般的にフォントファイルはライセンスが指定されていて、ものによってはゲームに同梱することが許されてなかったりする。
ここは比較的自由に使えるラインセンスのフォントを入手しないといけないわけだけど…。ありがたいことに、ドットコロンさんがいくつかのフォントファイルをCC0ライセンスで公開してくれているので、感謝しつつ使わせてもらうことにする。マジ助かります…。ありがたや…。
_ドットコロン
_Aileron | ドットコロン
_CC0について ― “いかなる権利も保有しない” | クリエイティブ・コモンズ・ジャパン
_CC0の日本語版が公開されました | 著作権のネタ帳
今回は Aileronフォントを使わせてもらうことにした。ダウンロードして解凍すると、中に otfファイルが入ってるので、今回は以下の2つを利用。
- Aileron-Black.otf
- Aileron-Bold.otf
エクスプローラ等からフォントファイルをGodot Engineのエディタ画面にドラッグアンドドロップ。これでフォントファイルがプロジェクトフォルダ内にコピーされる。
res://直下にコピーされてしまった。ドラッグして resourcesフォルダ内に移動。
resourcesフォルダ内に入った。
◎ フォントを指定。 :
インポートしたフォントを利用する。Messageノードの Custom Fontsプロパティをクリックして、「空」の部分をクリック。「新規DynamicFont」を選択。
「DynamicFont」の部分をクリックして、「Font Data」の「空」の部分をクリック。「読込み」を選ぶ。
Aileron-Black.otf を選んで、「開く」。
フォントが適用された。見た目が変わっている。これなら読めそう。
「DynamicFont」の部分をクリックして、「Font Data」の「空」の部分をクリック。「読込み」を選ぶ。
Aileron-Black.otf を選んで、「開く」。
フォントが適用された。見た目が変わっている。これなら読めそう。
◎ フォントサイズその他を設定。 :
フォントサイズその他を設定する。
これらの指定で、イイ感じの表示になってきた。
- Custom Fonts → Font → Settings → Size を 96 に。文字の大きさが変わる。
- Custom Fonts → Font → Settings → Use Filter を有効に。文字が少し滑らかに表示される。
- Custom Colors → Font Color Shadow を有効に。フォントに影がつく。
- Custom Constants → Shadow Offset X, Y を 12 に。影の位置をずらせる。
これらの指定で、イイ感じの表示になってきた。
◎ スコア表示の見た目を調整。 :
スコア表示の文字列と見た目を調整する。Scoreノードを選択。
Textプロパティに「SCORE: 0」と入力。
Messageノードと同様の手順でフォントを指定する。見た目がイイ感じになればOK。
表示位置を少し調整。Rect の Position や Size を変更してもいいし、GUIでキャンバス(?)上のノードをドラッグして位置調整してもいい。
Textプロパティに「SCORE: 0」と入力。
Messageノードと同様の手順でフォントを指定する。見た目がイイ感じになればOK。
表示位置を少し調整。Rect の Position や Size を変更してもいいし、GUIでキャンバス(?)上のノードをドラッグして位置調整してもいい。
◎ スタートボタンの見た目を調整。 :
[ ツッコむ ]
#3 [godot] Godot EngineでHUDシーンにスクリプトを追加
Godot Enigne 3.2.3 x64 の勉強を兼ねて、Apple Catcher っぽいゲームを作成中。
今回は、スコア、ゲームタイトル、スタートボタンの表示を担当するHUDシーンにスクリプトを追加する。後々、メインシーンから「スコア表示を更新しろ」だの「GAME OVERを表示しろ」だの色々指示されるはずなので、そういった処理を書く。
今回は、スコア、ゲームタイトル、スタートボタンの表示を担当するHUDシーンにスクリプトを追加する。後々、メインシーンから「スコア表示を更新しろ」だの「GAME OVERを表示しろ」だの色々指示されるはずなので、そういった処理を書く。
◎ スクリプトファイルを追加。 :
Hudノードを選んでおいて、右上のスクリプトをアタッチするボタンをクリック。
res://scripts/ 以下に Hud.gd というファイル名でスクリプトファイルを作成。
スクリプトを記述するエディタ画面が開かれた。
res://scripts/ 以下に Hud.gd というファイル名でスクリプトファイルを作成。
スクリプトを記述するエディタ画面が開かれた。
◎ スタートボタンを押したときのメソッドを用意する。 :
スタートボタンが押された時に、ゲーム開始処理を行わないといけない。そのあたりの処理を行うメソッドを用意する。
StartButtonノードを選択。
Buttonノードがマウスクリックされると、pressed() というシグナルが発行される。このシグナルにメソッドを接続する。ノードタブをクリックして、pressed() を選択して「接続」。
Hudノードを選択して「接続」。
Hud.gd 内に _on_StartButton_pressed() というメソッドが用意された。このメソッドの中にスタートボタンが押されたときに必要な処理を書いていけばいい。
StartButtonノードを選択。
Buttonノードがマウスクリックされると、pressed() というシグナルが発行される。このシグナルにメソッドを接続する。ノードタブをクリックして、pressed() を選択して「接続」。
Hudノードを選択して「接続」。
Hud.gd 内に _on_StartButton_pressed() というメソッドが用意された。このメソッドの中にスタートボタンが押されたときに必要な処理を書いていけばいい。
◎ スクリプト内容を記述。 :
Hud.gd にスクリプトを記述していく。
記述内容は以下。
_Hud.gd
内容を簡単に説明すると…。
カスタムシグナルについては少し説明が必要かもしれない。各ノードはあらかじめ色々なシグナルを持っているけれど、スクリプトファイルの最初のあたりに「signal hoge」と書いておけば、hogeシグナルを新規に用意することができる。
この hogeシグナルに何かメソッドを接続しておいて、どこかで「emit_signal("hoge")」を呼んでhogeシグナルを発行してやれば、そのタイミングで接続されているメソッドが実行される。
今回は、スタートボタンが押されたタイミングで、メインシーンに対して「スタートボタンが押されたよ」と知らせてゲーム開始処理を行いたいので、new_game というカスタムシグナルを用意した。後々、この new_game シグナルに、Main.gd 内のメソッドを接続する予定。
スクリプトを書けたので、F6キーを押して実行してみる。
スタートボタンが押された時に _on_StartButton_pressed() が呼ばれるけれど、そこでは「MessageノードとStartButtonノードを非表示にせよ」と書いてあるので…。スタートボタンをクリックするとその2つのノードが画面内で非表示になった。ちゃんとスクリプトは動いてる。
次回は、このHudシーンをメインシーンに合体させる。
記述内容は以下。
_Hud.gd
extends CanvasLayer signal new_game func _ready(): pass # Replace with function body. #func _process(delta): # pass func _on_StartButton_pressed(): $Message.hide() $StartButton.hide() emit_signal("new_game") func update_score(score): $Score.text = "SCORE: " + str(score) func show_message(text): $Message.text = text $Message.show() func hide_message(): $Message.hide() func show_startbutton(): $StartButton.show()
内容を簡単に説明すると…。
- _on_StartButton_pressed() : スタートボタンが押されたときの処理。
- update_score(score) : スコア表示更新処理。score には整数が入ってくる。
- show_message(text) : ゲームタイトルや「GAME OVER」等のメッセージ(?)を表示する。text には文字列が入ってくる。
- hide_messsage() : メッセージ表示を隠す。
- show_startbutton() : スタートボタンを表示する。
- $ノード名.show() で、そのノードを表示状態にできる。
- $ノード名.hide() で、そのノードを非表示状態にできる。
- signal new_game で、カスタムシグナルを作っている。
- emit_signal("new_game") でカスタムシグナルを発行。
カスタムシグナルについては少し説明が必要かもしれない。各ノードはあらかじめ色々なシグナルを持っているけれど、スクリプトファイルの最初のあたりに「signal hoge」と書いておけば、hogeシグナルを新規に用意することができる。
この hogeシグナルに何かメソッドを接続しておいて、どこかで「emit_signal("hoge")」を呼んでhogeシグナルを発行してやれば、そのタイミングで接続されているメソッドが実行される。
今回は、スタートボタンが押されたタイミングで、メインシーンに対して「スタートボタンが押されたよ」と知らせてゲーム開始処理を行いたいので、new_game というカスタムシグナルを用意した。後々、この new_game シグナルに、Main.gd 内のメソッドを接続する予定。
スクリプトを書けたので、F6キーを押して実行してみる。
スタートボタンが押された時に _on_StartButton_pressed() が呼ばれるけれど、そこでは「MessageノードとStartButtonノードを非表示にせよ」と書いてあるので…。スタートボタンをクリックするとその2つのノードが画面内で非表示になった。ちゃんとスクリプトは動いてる。
次回は、このHudシーンをメインシーンに合体させる。
[ ツッコむ ]
以上、1 日分です。