【Godot 4.3】アイワナ風トリガー針の作り方！

# はじめに

普段は[Cosense(Scrapbox)](https://scrapbox.io/Rutile3-Tech/)で技術記事を書いていますが、今回、[Godotのアドベントカレンダー](https://qiita.com/advent-calendar/2024/godot-engine)を見つけたのをきっかけに、Qiitaに記事を投稿してみることにしました。


# 概要

この記事では、以下のGIF画像のように、プレイヤーが特定の領域に侵入すると動き出す「トリガー針」の作り方を紹介します。

以下のGIFは完成イメージです。

![205f3eb30732e66d9f713408a61ad6ca.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213356/f5b6c384-8a71-b169-108e-4a8d0c80a6a4.gif)

# 環境
- Microsoft Windows 11 Home
- Godot Engine 4.3

# トリガー針の作り方

## 作成するシーンの基本構成

今回作成する「トリガー針」は、以下の2つのシーンを中心に構築します。

- 針（thorn）
    - 針そのものを表すシーン
    - トリガーがオンになると動作する
- 針トリガーエリア（thorn_trigger_area）
    - プレイヤーが領域に侵入すると、子ノードである「針」のトリガーをオンにする
    - 領域は呼び出し側で定義する

## 針のシーンを作成

まず、針のシーンとなる`thorn.tscn`を作成し、以下のようにノードを作成します。

- Thorn（Sprite2D型）
    - Area2D
      - CollisionPolygon2D

次に、`Thorn`ノードにスクリプトをアタッチし、`thorn.gd`として保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213356/d9a9e0da-a9c8-08cc-4f6e-46432ca8df27.png)

---------------------------------------

`Area2D`ノードのシグナルから`body_entered`を選択し、`thorn.gd`スクリプトに接続します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213356/cb8256c7-d4f1-da03-43e9-37369bcdfd3b.png)

---------------------------------------

接続後に、`thorn.gd`スクリプトを以下のように編集します。

```python:thorn.gd
extends Sprite2D


@export var is_move : bool = false # trueの場合、針が動く
@export var speed : float =  1.0 # 秒間１マス


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	add_to_group("thorn") # thornグループに設定


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	if is_move:
		# ~~~ 針の移動処理 ~~~


func _on_area_2d_body_entered(body: Node2D) -> void:
	if body.name == "PlayerCharacter":
		body.damaged() # プレイヤーが針に被弾した際の処理
```

### 実装のポイント

- `is_move`
    - 針トリガーエリアでオンにするためのフラグ
- `speed`
    - 各針の移動速度を個別に設定できるよう、エクスポートする
- `add_to_group("thorn")`
    - `_ready`関数で針を`thorn`グループに登録する
    - 後述する針トリガーエリアが複数の針を認識しやすくするための設定です

## 針トリガーエリアのシーンを作成

針トリガーエリアのシーンとなる`thorn_trigger_area.tscn`を作成し、以下のようにノードを作成します。

- ThornTriggerArea（Area2D型）

:::note warn
ノードにシェイプが設定されていないため警告が表示されますが、これは呼び出し元で設定するため、無視して問題ありません。
:::

次に、`ThornTriggerArea`ノードにスクリプトをアタッチし、`thorn_trigger_area.gd`として保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213356/10d67e21-e4d5-2495-ca31-c24908ca9f2e.png)

---------------------------------------

`ThornTriggerArea`ノードのシグナルから`body_entered`を選択し、`thorn_trigger_area.gd`スクリプトに接続します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213356/d4a85c3c-8195-aae5-8603-17f697e79924.png)

---------------------------------------

接続後に、`thorn_trigger_area.gd`スクリプトを以下のように編集します。

```python:thorn_trigger_area.gd
extends Area2D


# ~~~ _readyと_processはpassのみのため、記述を省略 ~~~


func _on_body_entered(body: Node2D) -> void:
	if body.name == "PlayerCharacter":
		for children in get_children():
			if children.is_in_group("thorn"):
				children.is_move = true
```

### 実装のポイント

- `for children in get_children():`
    - トリガーエリア内のすべての子ノードを順に処理する
- `if children.is_in_group("thorn"):`
    - 子ノードが`thorn`グループに属している場合にのみ、針を動作させる処理を実行する

## トリガー針をステージに配置

これまでに作成したトリガー針を、ステージに配置して動作させてみましょう。
ステージとなるシーンに`ThornTriggerArea`シーンを追加し、以下のようにノードを作成します。

- ThornTriggerArea
    - CollisionShape2D
    - Thorn1
    - Thorn2
    - Thorn3
    - …（必要に応じて追加）

`CollisionShape2D`ノードは、針トリガーエリアのシェイプとして機能します。
このシェイプがプレイヤーの侵入を検知する領域を定義します。

### 配置イメージ

以下は、トリガー針を配置した例です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213356/dc90c7a7-1b73-d506-ec68-6af41efe37e4.png)

### 動作の確認

`CollisionShape2D`ノードで設定した領域にプレイヤーが侵入すると、針が動き出します。
以下のGIFは完成イメージです。

![205f3eb30732e66d9f713408a61ad6ca.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213356/f5b6c384-8a71-b169-108e-4a8d0c80a6a4.gif)

# あとがき

私が調べた限りでは、Godotでトリガー針を作る方法を解説した記事は見当たりませんでした。
なので、この記事が少しでも皆さんの参考になれば嬉しいです！

記事のタイトルは「アイワナ風トリガー針」としましたが、個人的には『ノロイ ノ ゲエム』の飛んでくるギロチンのイメージが強いです。

技術的な疑問や改善点や、記事の記述の改善点があれば、ぜひコメントで教えてください！
ここまでお読みいただき、ありがとうございます。