【Godot Engine】2Dゲームチュートリアル(Part.3)

# 概要
Godot Engine での2Dゲーム作成チュートリアルの Part.3 (最終回)です。

前回はこちら

↓↓↓

* [【Godot Engine】2Dゲームチュートリアル(Part.2)](https://qiita.com/2dgames_jp/items/169b637aa8a0164c274c)


# クリックして破壊できるようにする
クリックしてGodotくんを破壊できるようにします。

## シグナルの追加
"Enemy"タブをクリックする、またはファイルシステムから「Enemy.tscn」をダブルクリックして、"Enemy"シーンを開きます。
![Godot_Engine_-_MyFirstGame_-_Enemy_tscn_と_Steam.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/ccffb902-28b9-8a0a-b3a8-345dff80eb74.png)

開いたら、インスペクタのとなりにある「ノード」をクリックします。
![Godot_Engine_-_MyFirstGame_-_Enemy_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/85c51711-8264-748c-52bb-2a2d67d194ee.png)

するとシグナルの一覧が表示されます。
シグナルとは、「別のオブジェクトと衝突した」「マウスでクリックされた」など、オブジェクトに対する影響を判定できる信号のことです。
色々とシグナルは用意されていますが、ここでは `CollisionObject2D > input_event()` を選んで、ダブルクリックします。
![Godot_Engine_-_MyFirstGame_-_Enemy_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/d4b8f848-5285-171c-2368-18693479a00c.png)

そのまま「接続」をクリック。
![Godot_Engine_-_MyFirstGame_-_Enemy_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/7a335d3f-0ede-e86f-e01d-e6d914027012.png)

するとシグナルを受け取る関数が追加されます。
![Godot_Engine_-_MyFirstGame_-_Enemy_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/dada92bc-15af-2539-8822-8cadda75d222.png)
ちなみに関数の左側に表示されている緑色のアイコンは「シグナルで接続されている」ことを示すものとなります。

この関数を以下のように修正します。

```gd:Enemy.gd
func _on_Enemy_input_event(viewport, event, shape_idx):
	# 何らかの入力イベントが発生
	if event is InputEventMouseButton:
		# マウスボタンの入力イベント
		if event.is_pressed():
			# クリックしたので、インスタンスを破棄
			queue_free()
```

`input_event()` は様々なイベントを受け取るので、まずはイベントがマウスボタンのイベントであるかどうかを判定します。
そしてそれがマウスクリックであれば `queue_free()` でインスタンスを破棄します。

実行して、マウスクリックでGodotくんが消えることを確認します。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/f0d263ba-1349-09e2-c4fc-1aa0a9510ceb.gif)

# クリア判定
ゲームクリア判定を作ります。

"Main"タブを選ぶ、または ファイルシステムから "Main.tscn" をダブルクリックして、Mainシーンを開きます。
![Godot_Engine_-_MyFirstGame_-_Enemy_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/234da532-bd60-5be3-c66f-d3d57e43c1a5.png)

次にMainノードを選択して右クリックし、「スクリプトをアタッチ」を選択します。
![Godot_Engine_-_MyFirstGame_-_Main_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/6ab46df7-e60d-438b-1d05-18eeedf7ec27.png)

そのまま「作成」をクリックします。
![Godot_Engine_-_MyFirstGame_-_Main_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/5cabb6ef-8df5-6931-4409-77df285abb86.png)

"Main.gd" スクリプトを以下のように修正します。

```gd:Main.gd
extends Node2D

func _process(delta):
	
	var all_destroyed = true
	# 子ノードをすべて調べる
	for node in get_children():
		if "Enemy" in node.name:
			# 敵が生存している
			all_destroyed = false
	
	if all_destroyed:
		# ゲームクリア
		OS.alert("ゲームクリア")
		
		# アプリケーションを終了する
		get_tree().quit()
```

子ノードをすべて調べて、ノード名に "Enemy" が含まれるオブジェクトが存在しなければゲームクリア、としています。

実行して、すべてクリックするとゲームクリアとなることを確認します。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/48463b68-6521-363f-39be-67b736ffa9c3.gif)

# パーティクルを実装する
最後にGodotくんが消滅するときのパーティクルを実装します。
タブの右隣にある「＋」をクリックして、シーンを追加します。
![Godot_Engine_-_MyFirstGame_-_Main_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/60cb3ac3-9af2-3677-96e0-5f7508fb740d.png)

「＋　その他のノード」をクリックします。
![Godot_Engine_-_MyFirstGame.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/6df7c46d-da9f-c275-1877-3f9c0dc0f9e7.png)

検索欄に「Particle」と入力して `CPUParticles2D` を選んで、作成ボタンをクリックします。
![Godot_Engine_-_MyFirstGame.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/07b562bd-774f-70eb-b212-4ee9e49f4d23.png)

作成された `CPUParticles2D` のノード名を 「Particle」に変更します。
![Godot_Engine_-_MyFirstGame____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/42fd444e-6ec1-a30e-1715-56434da372fc.png)

いったん、`Ctrl+S (Cmd+S)` でシーンを「Particle.tscn」として保存します。
![Godot_Engine_-_MyFirstGame____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/23791f33-83dd-dab4-81d0-42fb6fef1d2e.png)

## パーティクルの設定
### テクスチャの設定
Particleノードを選択して、ノードタブから「インスペクタ」に戻します。
![Godot_Engine_-_MyFirstGame_-_Particle_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/d94ae4b2-8462-9f63-38e3-92d2c4e232b1.png)

インスペクタから、`Drawing > Texture > [空]` をクリックして、「読み込み」を選択します。
![Godot_Engine_-_MyFirstGame_-_Particle_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/5952b770-34fc-a1a4-c318-4b4bff025677.png)

パーティクルに使用する画像選択画面が表示されるので、"icon.png" を選びます。
![Godot_Engine_-_MyFirstGame_-_Particle_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/8928076e-34b1-a24d-8b2c-ea4a17caf5b4.png)

すると、Godotくんが生成され続けるパーティクルとなります。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/a20608f4-2fa1-4fa5-5695-0080be5e8ea7.gif)

### 初期速度の設定 `Initial Velocity > Velocity`
発生時の初期速度を設定します。
`Initial Velocity > Velocity`の値を「150」に変更します。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/f7d757fa-7580-ecc6-04da-8ce4df98ad11.gif)
すると右方向に向けて放出されるようになります。

### 発生方向の変更 `Direction > Spread`
発生方向を全方向に変更します。
`Direction > Spread` の値を「180」にすると±180度となるので、全方向に放出されるようになります。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/c5140a10-9c10-fc03-77b9-1fec4a9b887d.gif)

### サイズの変更 `Scale > Scale Amount`
サイズが大きすぎるので、`Scale > Scale Amount` を 0.5 にして小さくします。
![Godot_Engine_-_MyFirstGame_-_Particle_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/3710ff2b-579b-0bab-5796-2d68c53c776c.png)

また時間経過に合わせてサイズを小さくしたいので、`Scale Amount Curve > [空]` をクリックして、「新規カーブ」を選びます。
![Godot_Engine_-_MyFirstGame_-_Particle_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/178bb116-56bf-67b6-b210-d742da3ca64d.png)
作成されたCurveをクリックして、カーブグラフを表示し、右クリックしてポイントを追加し、右下がりのカーブを作成します。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/0da08fd9-31d8-9013-c29d-09b054092ee5.gif)

すると時間経過で小さくなるパーティクルとなります。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/4d734b16-0fc5-c633-b9cd-134df9512cd7.gif)

### 放出タイミングの調整 `Time > Explosiveness`
クリックでの破壊時にまとめて放出したいので、`Time > Explosiveness` を「1」にします。
![Godot_Engine_-_MyFirstGame_-_Particle_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/fb6f4d7d-d789-a193-c2ae-8414c203f0db.png)

この指定をすると、まとめて放出されます。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/9c31fd7c-7620-8726-ff08-55b113848cce.gif)

### One Shot再生にする `Time > One Shot`
このパーティクルは一度再生したら終了するタイプなので「One Shot」に変更します。
`Time > One Shot`にチェックを入れると一度きりの再生となります。
![Godot_Engine_-_MyFirstGame_-_Particle_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/9e2170d5-2b7b-1230-bba7-61c8e9d82437.png)

再び動作を確認したい場合は、`One Shot`の指定は外して、`Emitting` にチェックを入れます。
`One Shot`にチェックを入れたままにすると、`Emitting`をクリックするたびに再生されます。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/423fcc93-a0cd-0e8b-42d6-c133ef06c023.gif)

もし`One Shot`のチェックを外した場合は、チェックを入れるようにしておいてください。

## スクリプトのアタッチ
Particleノードを右クリックして、スクリプトのアタッチを選びます。
![Godot_Engine_-_MyFirstGame_-_Particle_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/38ff455e-4937-b0a3-eff5-bf20f3b53d0e.png)
「作成」を選択します。
![Godot_Engine_-_MyFirstGame_-_Particle_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/1d119067-b838-a965-9dce-079fd2affd98.png)

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

```gd:Particle.gd
extends CPUParticles2D

func start(pos):
	# 放出開始
	emitting = true
	# 位置を設定
	position = pos

func _process(delta):
	if emitting == false:
		# 再生終了
		queue_free()
```

`start()` で座標を指定して放出を開始します。
また `emitting` で終了判定をします。

# Enemyからパーティクルを呼び出す
Enemyシーンを選択して、Enemy.gd スクリプトを以下のように修正します。

```gd:Enemy.gd
extends Area2D

# パーティクルオブジェクト
var Particle = preload("res://Particle.tscn")

# 画面サイズ
var screen:Rect2

# 移動速度
var velocity:Vector2

……
```

`var Particle = preload("res://Particle.tscn")` という記述が追加されています。これは Particleシーンを Enemy.gd で使用するための記述となります。

そして後半の `_on_Enemy_input_event()`を修正します。

```gd:Enemy.gd
func _on_Enemy_input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton:
		# マウスボタンの入力イベント
		if event.is_pressed():
			# クリックしたので、インスタンスを破棄
			queue_free()
			
			# パーティクルを生成
			var p = Particle.instance()
			# パーティクル再生開始
			p.start(position)
			# ルートノードに設定する
			var root_node = get_parent()
			root_node.add_child(p)
```

Godotくん破壊時にパーティクルを生成する記述となります。
現在のノード構成では "Enemy" の上に Mainノードがあることが決まっているので、`get_parent()` で親ノードを取得して、`add_child()` でぶら下げています。

では、実行してGodotくんの破壊パーティクルが再生されることを確認します。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/b1afd47c-cde4-5947-cc38-01069f201a52.gif)

パーティクルの挙動が今ひとつな感じなので、気になる方はより詳しい使い方を以下のページにまとめていますので参考になるかもしれません。

* [【Godot】2Dパーティクルの使い方](https://qiita.com/2dgames_jp/items/2a37c75e9bf65687bfaf)


# 最後に

ここまでできたら、あとは色々なチュートリアルを試してみるのが良いと思います。
公式のチュートリアルでは、スプライトアニメーションやボタンの作成方法など、色々な機能が使われているので勉強になると思います。

* [最初のゲーム -- Godot Engine](https://docs.godotengine.org/ja/stable/getting_started/step_by_step/your_first_game.html)

あと、個人的にシューティングを作るときに悩んだことは以下のページにまとめましたので、ひょっとしたら参考になるかも……。

* [【Godot】2Dシューティングゲームを作るときのポイントまとめ](https://qiita.com/2dgames_jp/items/a1db3a0a6d67e02a7d43)

----
----

※2021.3.25 追記
フラッピーバードを作るチュートリアル記事を作成しました

* [【Godot Engine】フラッピーバードを作るチュートリアル (Part.1)](https://zenn.dev/syun77/articles/8adb3d11ace66f)

![ebp6q79hc7t6geipzxcwt702fxho.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/40cbe66f-d142-f5d4-5ea0-250977a6bdc8.gif)
このようなゲームを作る手順を紹介しています。