昨日、GameManagerらしきものをGodotで作成することはできたので、Enemy.gd(これで、Enemyスクリプトを表すらしいです。)
を一気に進めていこうと思います。
Unityで作成した時のEnemyControllerには、下記の関数がありました。
・SetParameter関数
・SetEnemyColor関数
・Moving関数
・ScaleVertically関数
・OnCollisionEnter2D関数
EnemyGeneratorクラスからEnemyが生成されるタイミングで、SetParameter関数とSetEnemyColor関数が呼ばれ、
GameManagerの設定値からEnemyの初期設定を行います。
Moving関数はEnemyを徐々に下に移動させる機能と、色変わりもしくは成長する機能を持ちます。
ScaleVertically関数は、画面に動きが欲しかったので、EnemyをゆっくりY方向に伸縮させています。
今日のところは、これらをGDScript化していきます。
まずは、変数の宣言に、SetParameter関数とSetEnemyColor関数を作ります。
extends Area2D @export var Color_Change_Span :float #敵の色が変わるスピード @export var Growth_Span :float #敵が大きくなるスピード @export var Drop_Down_Speed :float #敵が落ちてくるスピード @export var Living_Time :float #敵が生きている時間 var Next_Color_Change_Time :float #次に色が変わる時間 var Next_Growth_Time :float #次に大きくなる時間 var Enemy_Color :int #敵の色 var Enemy_Size :int #敵の大きさ @export var Puru_puru_Time :float #ぷるぷるタイム var isIncreasing :bool =true #呼吸方向判定用 var Base_Scale :Vector3 #基本のスケール @export var Scale_Change :float #スケールの増減値 @export var Scale_Interval :float #スケール変更の間隔 var Color_Change_Timer :float var Puru_puru :bool var Puru_puru_Counter :int var Color_Changing :bool var Base_Size :float =0.4 #Enemy_Sizeの基準値 var Base_Growth_Size :float =0.05 #Enemy_Size が1増えた時の成長量の基準値 func _ready(): _Scale_Vertically() func _Set_Parameter(): Living_Time=0 Color_Change_Span=GameManager.Set_Color_Change_Span-GameManager.Game_Level*0.15 Drop_Down_Speed=GameManager.Set_Drop_Down_Speed+GameManager.Game_Level*0.02 Next_Color_Change_Time=Color_Change_Span Next_Growth_Time=Growth_Span # _Moving() _Scale_Vertically() 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) pass
SetParameter関数
func _Set_Parameter(): Living_Time=0 Color_Change_Span=GameManager.Set_Color_Change_Span-GameManager.Game_Level*0.15 Drop_Down_Speed=GameManager.Set_Drop_Down_Speed+GameManager.Game_Level*0.02 Next_Color_Change_Time=Color_Change_Span Next_Growth_Time=Growth_Span _Scale_Vertically()
ここでは何も難しいことはしていません。
GameManagerというグローバルクラスから、
・Game Level変数 ・・・ゲームレベルを格納
・Set_Color_Change _Span変数 ・・・基本の色変わりの間隔を格納
・Set _Drop _Down_Speed変数 ・・・基本の落下速度を格納
を取得してきて、計算した結果をプライベート変数のColor_Change_Span変数と、Drop_Down_Speed変数に代入しています。
SetEnemyColor関数
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) pass
ここは昨日作成した通りです。
GameManagerのColors配列変数から色番号に沿って色情報を取得して、Sprite2Dの色を設定しています。
Moving関数 → _physics_process関数
func _physics_process(delta): # ← deltaを渡している。 Living_Time+=delta print("Living_Time ",Living_Time) if GameManager.Game_Over: #将来、ゲームオーバーの処理を書く場所 pass position.y+=GameManager.Set_Drop_Down_Speed #今だけの暫定。完成時にはDrop_Down_Speedに置き換える。 if position.y<+5: # $QueueFree() # Enemyをオブジェクトプールに返す処理を書く pass if Living_Time>Next_Color_Change_Time: Color_Change_Timer+=delta if Color_Change_Timer>Puru_puru_Time: Puru_puru=!Puru_puru Color_Change_Timer=0 Puru_puru_Counter+=1 if Puru_puru: $Sprite2D.scale=Vector2( (Base_Size+Enemy_Size*Base_Growth_Size)-Scale_Change/2, (Base_Size+Enemy_Size*Base_Growth_Size)-Scale_Change/2) else: $Sprite2D.scale=Vector2( (Base_Size+Enemy_Size*Base_Growth_Size)+Scale_Change/2, (Base_Size+Enemy_Size*Base_Growth_Size)+Scale_Change/2) if Puru_puru_Counter>6: Puru_puru_Counter=0 Puru_puru=false match randi_range(0,1): 0: _Set_Enemy_Color(GameManager._Set_Enemy_Color()) Next_Color_Change_Time+=Color_Change_Span pass 1: Enemy_Size+=1 $Sprite2D.scale=Vector2( (Base_Size+Enemy_Size*Base_Growth_Size), (Base_Size+Enemy_Size*Base_Growth_Size)) Next_Color_Change_Time+=Color_Change_Span pass||<
今日のメインはここです🤣
Unityではasync/awaitで行っていましたが、よくよく見返せば、別に非同期である必要はなかったので、普通にUnityでいうFixedUpdateの
_physics_process(delta)関数で作る事にしました。
Unityと同じく、ほぼ毎フレームで呼び出される関数です。
func _physics_process(delta): # ← deltaを渡している。
Living_Time+=delta
いきなり、Unityと異なる場所です。
GodotではTime.deltaTimeはdeltaと書きます。しかも、関数で引数で渡しておかないと関数内で使用できません。
position.y+=GameManager.Set_Drop_Down_Speed #今だけの暫定。完成時にはDrop_Down_Speedに置き換える。
昨日も書きましたが、Godotではシーン内のノードのプロパティは比較的簡単にアクセスすることができます。
今回は、スクリプトがアタッチされているArea2D自身のpositionを変更したいのですが、
positionはUnityと同じようにTransformの下になるのですが、Godotの場合、positionと書くだけで大丈夫です。
大きな違いは、Unityでは2Dも3DもpostionやscaleはVector3ですが、Godotの場合は2DではpositionもscaleもVector2になります。
Unityの感覚でVector3で計算しようとするとエラーになってしまうので、最初のうちは注意が必要そうです。
match randi_range(0,1): 0: _Set_Enemy_Color(GameManager._Set_Enemy_Color()) Next_Color_Change_Time+=Color_Change_Span pass 1: Enemy_Size+=1 $Sprite2D.scale=Vector2( (Base_Size+Enemy_Size*Base_Growth_Size), (Base_Size+Enemy_Size*Base_Growth_Size)) Next_Color_Change_Time+=Color_Change_Span pass
randi_rangeというのは、乱数を発生させる関数で、引数で範囲を指定します。
randi_range(0,1):
最初の引数が最小値を示し、二番目の引数が最大値を示します。
ですので、この場合は0か1の乱数が作成されます。
少数の乱数を作成したい場合は、
randf_range(0.0,1.0):
この様に、randの次の文字をintのiから、floatのfにかえて引数も少数表記にします。
これで0〜1.0の少数の乱数が作成されます。
次にmatchですが、これはUnityでいうSwitch分岐になります。
つまり、乱数で0か1を作成し、その数字に合わせて、成長か色変わりかを判定する仕組みです。
ScaleVertically関数
func _Scale_Vertically(): while true: if GameManager.Game_Over: break await get_tree().create_timer(Scale_Interval).timeout if isIncreasing: scale=Vector2( (Base_Size+Enemy_Size*Base_Growth_Size), (Base_Size+Enemy_Size*Base_Growth_Size)*0.96) else: scale=Vector2( (Base_Size+Enemy_Size*Base_Growth_Size), (Base_Size+Enemy_Size*Base_Growth_Size)*1.02) # 増減の方向を切り替え isIncreasing = not isIncreasing
今日の最後です。
Godotは3.5版から4版の変更でかなり破壊的な改革が入った様で、async・awaitも仕様が変わった様です。
まだしっかりと公式ドキュメントを読みきれていないのですが、どうも、関数内にawaitがあると、その関数は非同期として扱われるようです。
ですので、この関数の様にwhile trueで無限ループする処理を作っても、問題ありませんでした。
await get_tree().create_timer(Scale_Interval).timeout
Godot特有の書き方で、変数宣言したScale_Intervalの秒数のTimerを作成して、そのTimerがタイムアウトするまでawait。
つまり、Scale_Interval秒だけawaitしてくれます。
これで基本の敵の挙動はできたから、次はEnemyGeneratorかなあ🧐
www.youtube.com