ゲーム制作勉強中!あこがれだったプログラマーに今からなろう!

昔、あこがれていたプログラマー。今からでも勉強してみようと思い立ち、チャレンジ開始! 勉強メモや、悪戦苦闘な日々の記録です。

Unity経験者によるGodot実践メモ:GameManagerっぽいものについて

ゲームエンジンです。
ゲームエンジンはやっぱり、ゲームを作っていかないと勉強にはならないので、Unityで作成したゲームをGodotで作成しようと思います。
作成するゲームは、これです。

youtube.com

Unityroomの1WSSで作成した、ColorChangePanicをGodotでもう一回最初っから作成してみようと思います。

当時の記憶を呼び覚ましながら、Unityのプロジェクトを確認してみると、
敵はObjectPoolクラスから、EnemyGeneratorクラスにより生成され、
敵自身のEnemyControllerクラスのSetParameter関数とSet EnemyColor関数で初期設定される仕組みです。
生成のタイミングや敵の色、敵の動きの速さを決める設定はGameManagerクラスが管理しています。

ここまで記憶を辿ってみて、いきなりGodotのチュートリアルだけでは越えられない壁が3つある事に気づきました😅

①. ObjectPoolはUnityの組み込み機能で作成されているので、そのままGodotに移植する方法が判らない。
②. GameManagerをGodotで作成する方法が判らない。
③.  UniTaskの様にasync/awaitが可能なのか判らない。
・・・🤣

まぁ、まだ勉強し始めのシステムなので、細かいことは気にせず、とりあえず簡単そうなGameManagerの作り方を考えてみます。

Game Managerといってもやっているのは、各クラスで共用する変数の管理くらいです。
Godotの変数は基本的には、宣言したスクリプトの中でしか使えないprivate変数なのですが、
調べてみると、他クラスで共有できるGlobal変数を作成する方法もあるにはありそうです。

他シーンとデータを共有するリソースという考え方があるようで、それらしい記事を見つけることができました。
1-notes.com

この記事を参考にGameManagerっぽいものを作成してみます。
まず、Unityでいう「空のオブジェクト」に相当するらしい、Node(何の機能もない、ただのNode)を作成し、
その名前をGameManagerにします。

ここに共用する変数を宣言したスクリプトをアタッチします。

extends Node

@export var Set_Color_Change_Span :float = 0.1 #敵の色が変わるスピード

@export var Game_Level :int = 1 #ゲームのレベル

@export var Set_Drop_Down_Speed :float =0.1 #敵が落ちるスピード


var Colors:Array[Vector3] = [Vector3(0.8867924,0.3304556,0.364517),
							Vector3(0.3941794,0.4784876,0.8113207),
							Vector3(0.8679245,0.8367506,0.2824848),
							Vector3(0.3406906,0.8301887,0.4169851),
							Vector3(1,.9992402,0.9858491)] #色のセット

public変数という概念がない様なので、ここでもprivate変数の様に宣言してもいいみたいです。

ちょっと話はそれますが、GDScriptは{ }の代わりに、インデントという空間で境界を判断している仕組みです。
なので、長すぎる行を途中で改行して見やすくすることはできないと誤解していましたが、
今回の例の様に、問題なく途中改行できる様ですね。😃

ここまでできたら、このGameManagerをシーンとして保存します。
そして、Godotエディタからプロジェクトプロジェクト→プロジェクト設定
そして、開いたプロジェクト設定の画面で作成したGamaManagerシーンを登録し、グローバル変数有効にチェックを入れます。


これでGameManagerの変数はGlobal変数として使用可能になった様です。



では、早速実験です。
Area2Dノードをコアノードにして、CollisonSharpe2DとSprite2Dを子ノードにして、Enemyシーンを作成。

試しに、

extends Area2D

var Enemy_Color :int #敵の色
@export var TestInt :int

func _ready():
	print("Set_Drop_Down_Speed ",GameManager.Set_Drop_Down_Speed)#Game Managerの変数の変更前を確認
	GameManager.Set_Drop_Down_Speed=0.2#GameManagerの変数を変更する実験
	_Set_Enemy_Color(TestInt)


func _Set_Enemy_Color(color:int):#intを引数で受け取る。
	Enemy_Color=color
	$Sprite2D.modulate=Color(GameManager.Colors[Enemy_Color].x,GameManager.Colors[Enemy_Color].y,GameManager.Colors[Enemy_Color].z,1)
	print("Set_Drop_Down_Speed ",GameManager.Set_Drop_Down_Speed)#Game Managerの変数が変更できているか確認

というスクリプトを作成し、Area2Dノードにアタッチします。

Unityだと関数側の引数の指定方法は

Set_Enemy_Color(int color)

ですが、Godotの場合は変数名が先なので、慣れるまで間違いそうです😅

func _Set_Enemy_Color(color:int):#intを引数で受け取る。

そして、Godotの場合、スクリプトがアタッチされているノードの子ノードのプロパティは基本的には宣言無しに使用できる様です。

今回の場合、色を変えたいSprite2Dノードは、スクリプトがアタッチされているArea2Dノードの子になっているので、
Area2Dのスクリプトは、Sprite2Dノードのプロパティを変数に取り込んだりせずに使用可能です。

Unityの場合はそれでもGetComponentが必要ですが、Godotの場合は、そのノードのパスさえ判れば問題ない様です。
今回のスクリプト

$Sprite2D.modulate=Color(GameManager.Colors[Enemy_Color].x,GameManager.Colors[Enemy_Color].y,GameManager.Colors[Enemy_Color].z,1)

$Sprite2Dは、get_node("Sprite2D") の略式の記載方法で、シーン内から「Sprite2D」という名前のノードを探してきます。
見つかったパスを使って、Sprite2D→modulate→colorに、先ほど作成してきたGameManagerのColors変数から指定のVector3を受け取って設定する寸法です。

また、同じようにGameManagerの変数を変更することができるか、

	GameManager.Set_Drop_Down_Speed=0.2#GameManagerの変数を変更する実験

Ready関数で実験しています。
変数変更の次の行の

	print("Set_Drop_Down_Speed ",GameManager.Set_Drop_Down_Speed)#Game Managerの変数の変更前を確認

は、UnityでいうDebug .logに当たる処理で、コンソールに指定した文字を書くことができます。

結果ですが、
youtu.be
インスペクターで指定したTestIntの数値に沿って、GameManagerからきちんと色を取得できていている様子です。
GameManagerの変数も問題なく変更することができました。

これで、どうやら、UnityのGameManagerの作成は大丈夫そうです。