📝

【Godot Engine】フラッピーバードを作るチュートリアル (Part.3)

2021/03/10に公開

概要

この記事は Godot Engine でフラッピーバードを作るチュートリアルとなります。

前回の記事はこちらから
https://zenn.dev/syun77/articles/dcae7c4083985e

土管シーンの作成

障害物となる土管シーンを作成します。
Playerシーンのタブのとなりにある「+」をクリックします。

新しいシーンが作成されるので、「+その他のノード」をクリックします。

型は StaticBody2D を選びます。

作成したらノードの名前を「Dokan」に変更します。

変更したら Ctrl+S (Cmd+S) で土管シーンを保存しておきます。

土管画像をプロジェクトに追加

以下の画像を "dokan.png" として保存してプロジェクトに追加します。

これを保存したら、ドラッグ&ドロップで追加します。

土管画像をスプライトにする

プロジェクトに追加した "dokan.png" をキャンバスにドラッグ&ドロップします。

土管スプライトの位置を調整する

土管スプライトを中央揃えにします。
「dokan」ノードを選択します。

そしてインスペクタから、Node2D > Transform > Position の回転アイコンをクリックして、(x, y) の値を (0, 0) にリセットします。

すると土管スプライトが中央揃え(原点を中心)の配置となります。

土管のコリジョンを作成する

ルートノードの「Dokan」を右クリックして、「+子ノードを追加」を選びます。

CollisionShape2D を選んで「作成」ボタンをクリックします。

すると CollisionShape2Dノードが追加されます。

そうしたらインスペクタから CollisionShape2D > Shape > [空]をクリックして、「新規 RectangleShape2D」を選びます。

キャンバスを拡大すると中心に矩形のコリジョンが設定されていることが確認できます。

コリジョンサイズを調整

コリジョンの角にあるハンドルをドラッグして、コリジョンが土管を覆うように広げます。

土管を動かす

プレイヤーとの衝突をテストするために、土管を動かすスクリプトを実装します。
「Dokan」ルートノードを選択して、スクリプトアイコンをクリックします。

スクリプトアタッチのダイアログが表示されるので、そのまま「作成」をクリックします。

Dokan.gdスクリプトには以下のように記述します。

Dokan.gd
extends StaticBody2D

# 移動速度
var velocity = Vector2(-100, 0)

func _process(delta):
	# 位置に速度を足し込む
	position += velocity * delta

土管の動作を確認する

Ctrl+S (Cmd+S) で変更を保存して、「Main」シーンのタブに切り替えます。

「2D」をクリックして2Dモードに切り替えます。

そうしたら、「Dokan.tscn」をMainシーンにドラッグ&ドロップします。

もし以下のように "bg_back" ノードの下に配置される場合は、

"Dokan"ノードをドラッグ&ドロップして "Main"ノードの直下になるように移動しておきます。

左上の「▶」をクリックして実行してみます。

すると土管が右から左に移動するのが確認できます。

プレイヤーとの当たり判定を確認する

次にプレイヤーを Mainシーンに配置します。

テスト用にプレイヤーの位置を原点からずらしているので、少し斜め上に配置すると良い位置になります。

実行して当たり判定を確認します。

するとプレイヤーが土管に刺さるような挙動となります。
これは土管にぶつかったときにプレイヤーは特に衝突の反動を入れていないためです。
KinematicBody2Dを使った場合は、衝突時の処理を自分で作る必要があります。

プレイヤーに衝突の反動を入れる

Player.gd を開いて以下のように修正します。

Player.gd
extends KinematicBody2D

# 重力
const GRAVITY_POWER := 1000

# ジャンプ力
const JUMP_POWER := -400

# 移動速度
var velocity := Vector2()

+# ジャンプできるかどうか
+var can_jump := true

+# スプライト
+onready var sprite := $sprite

func _process(delta):
	# 重力を加算
	velocity.y += GRAVITY_POWER * delta
	
-	if Input.is_action_just_pressed("ui_accept"):
+	if can_jump and Input.is_action_just_pressed("ui_accept"):
		# Spaceキーでジャンプ処理
		velocity.y = JUMP_POWER

	if position.y < 0:
		# 画面上にはみ出さないようにする
		velocity.y = 100
		
	if position.y > 600-64:
		# 画面下に落ちないようにオートジャンプ
		velocity.y = JUMP_POWER

-	# 移動処理を行う
-	move_and_collide(velocity * delta)
+	# 移動と衝突処理を行う
+	var collision = move_and_collide(velocity * delta)
+	if collision:
+		# 衝突したのでジャンプできなくする
+		can_jump = false
+		# 左方向に吹き飛ばす
+		velocity.x -= 300
+		# さらに移動量を加える
+		move_and_collide(velocity * delta)

+	if can_jump == false:
+		# 吹っ飛び中は回転する
+		sprite.rotation -= 10 * delta

行頭に「-」がついている行が削除する行で、「+」が追加する行となります。
can_jump変数を追加して、この変数がtrueの場合のみジャンプできるようにしました。

実行して動作を確認します。

プレイヤースクリプトをリファクタリング

Player.gd_process() が長くなりすぎたので、関数を短くします。

Player.gd
extends KinematicBody2D

# 重力
const GRAVITY_POWER := 1000

# ジャンプ力
const JUMP_POWER := -400

# 移動速度
var velocity := Vector2()

# ジャンプできるかどうか
var can_jump := true

# スプライト
onready var sprite := $sprite

func _process(delta):
-	# 重力を加算
-	velocity.y += GRAVITY_POWER * delta
-	
-	if can_jump and Input.is_action_just_pressed("ui_accept"):
-		# Spaceキーでジャンプ処理
-		velocity.y = JUMP_POWER
-
-	if position.y < 0:
-		# 画面上にはみ出さないようにする
-		velocity.y = 100
-		
-	if position.y > 600-64:
-		# 画面下に落ちないようにオートジャンプ
-		velocity.y = JUMP_POWER
-
-	# 移動と衝突処理を行う
-	var collision = move_and_collide(velocity * delta)
-	if collision:
-		# 衝突したのでジャンプできなくする
-		can_jump = false
-		# 左方向に吹き飛ばす
-		velocity.x -= 300
-		# さらに移動量を加える
-		move_and_collide(velocity * delta)
-	if can_jump == false:
-		# 吹っ飛び中は回転する
-		sprite.rotation -= 10 * delta
		
+	# 移動処理を行う
+	_update_moving(delta)
+	
+	# 衝突処理
+	_update_collision(delta)
+	
+	# アニメーションの更新
+	_update_anim(delta)


+# 移動処理を行う
+func _update_moving(delta):
+	# 重力を加算
+	velocity.y += GRAVITY_POWER * delta
+	
+	if can_jump and Input.is_action_just_pressed("ui_accept"):
+		# Spaceキーでジャンプ処理
+		velocity.y = JUMP_POWER
+
+	if position.y < 0:
+		# 画面上にはみ出さないようにする
+		velocity.y = 100
+		
+	if position.y > 600-64:
+		# 画面下に落ちないようにオートジャンプ
+		velocity.y = JUMP_POWER

+# 衝突処理を行う
+func _update_collision(delta):
+	# 移動と衝突処理を行う
+	var collision = move_and_collide(velocity * delta)
+	if collision:
+		# 衝突したのでジャンプできなくする
+		can_jump = false
+		# 左方向に吹き飛ばす
+		velocity.x -= 300
+		# さらに移動量を加える
+		move_and_collide(velocity * delta)

+# アニメーションの更新
+func _update_anim(delta):
+	if can_jump == false:
+		# 吹っ飛び中は回転する
+		sprite.rotation -= 10 * delta

移動処理を _update_moving() 、衝突処理を_update_collision()、アニメーションの更新を _update_anim()としました。
正確には move_and_collide() は移動と衝突を同時に行っているのですが、ひとまずこのようにしています。

実行して、修正前と同じ挙動を取るかどうか確認します。

Player.gd のすべてのコード

差分ファイルとしているのが逆にわかりにくいかもしれないので、ここまでの Player.gd をのせておきます。

Player.gd
extends KinematicBody2D

# 重力
const GRAVITY_POWER := 1000

# ジャンプ力
const JUMP_POWER := -400

# 移動速度
var velocity := Vector2()

# ジャンプできるかどうか
var can_jump := true

# スプライト
onready var sprite := $sprite

func _process(delta):	
	# 移動処理を行う
	_update_moving(delta)
	
	# 衝突処理
	_update_collision(delta)
	
	# アニメーション
	_update_anim(delta)


# 移動処理を行う
func _update_moving(delta):
	# 重力を加算
	velocity.y += GRAVITY_POWER * delta
	
	if can_jump and Input.is_action_just_pressed("ui_accept"):
		# Spaceキーでジャンプ処理
		velocity.y = JUMP_POWER

	if position.y < 0:
		# 画面上にはみ出さないようにする
		velocity.y = 100
		
	if position.y > 600-64:
		# 画面下に落ちないようにオートジャンプ
		velocity.y = JUMP_POWER

# 衝突処理を行う
func _update_collision(delta):
	# 移動と衝突処理を行う
	var collision = move_and_collide(velocity * delta)
	if collision:
		# 衝突したのでジャンプできなくする
		can_jump = false
		# 左方向に吹き飛ばす
		velocity.x -= 300
		# さらに移動量を加える
		move_and_collide(velocity * delta)

# アニメーションの更新
func _update_anim(delta):
	if can_jump == false:
		# 吹っ飛び中は回転する
		sprite.rotation -= 10 * delta

プレイヤーのアニメーションを実装する

土管との衝突を作ったので、ついでにプレイヤーのアニメーションを実装しておきます。
プレイヤーのアニメーション番号は以下のようになっていました。

これをもとにアニメーションの実装を行います。
Player.gd_update_anim()を以下のように修正します。

Player.gd
# アニメーションの更新
func _update_anim(delta):
+	# 基本
+	sprite.frame = 0
+	if velocity.y < 0:
+		# 上昇中
+		sprite.frame = 1
	if can_jump == false:
		# 吹っ飛び中は回転する
		sprite.rotation -= 10 * delta
+		# ダメージ画像にする
+		sprite.frame = 2

では実行して操作や状態によってスプライトが変化することを確認します。

次回

第4回に続きます
https://zenn.dev/syun77/articles/f4991e756a893d

Discussion