【Godot】Camera2Dで画面を揺らす方法

# 概要
この記事では、Godot Engineで画面を揺らす方法について説明をします。

# Camera2Dを使って画面をスクロールさせる
まずは `Camera2D` を使用して、画面のスクロールを実装してみます。

2Dシーンを作成して、ノード名を "Main" に変更します。
そして、背景画像 "bg.png" をプロジェクトに追加し、画面上に配置します。

## Camera2Dの作成
次に `Camera2D` を作成します。
![Godot_Engine_-_TestCamera_-_Main_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/44ebce34-2642-9f03-a046-549896271116.png)

ノード構成は以下のようになりました。
![Godot_Engine_-_TestCamera_-_Main_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/7f287c80-85c4-7a60-6b82-a2407838618d.png)

そしてインスペクタから `Current` にチェックを入れて、現在使用するカメラとします。
![Godot_Engine_-_TestCamera_-_Main_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/55ac07a6-1a52-5755-9563-73fcc94b5ec8.png)

## カメラにスクリプトをアタッチ
`Camera2D` にスクリプトをアタッチします。スクリプトは以下のように記述します。

```gd:Camera2D.gd
extends Camera2D

func _process(delta):
	# マウスカーソルが中心になるようにする
	offset = get_viewport().get_mouse_position()
```

実行すると、マウスカーソルの位置に合わせて、画面がスクロールします。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/3cc04986-bf74-5f8a-95d4-5b9878116a15.gif)


## 簡単な画面揺れの実装
Spaceキーを押したら画面揺れが開始するようにします。

```gd:Camera2D.gd
extends Camera2D

# 揺れ時間
var time = 0

func shake():
	# 残り時間の幅でランダムに揺らす
	# 画面比率 (1024:60) 固定
	offset.x = 32    * rand_range(-1, 1) * time
	offset.y = 18.75 * rand_range(-1, 1) * time

func _ready():
	# カメラを画面の中心に移動 (解像度を 1024 x 600とした場合)
	position.x = 1024 / 2
	position.y = 600 / 2

func _process(delta):
	if time > 0:
		# 揺れ時間が残っていれば揺らす
		time = max(0, time - delta)
		shake()

	if Input.is_action_just_pressed("ui_accept"):
		# Spaceキーで揺れ開始
		time = 1 # 1秒
	
```

残り時間に合わせて揺れ幅を変更するシンプルな画面揺れです。

![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/75f06083-6075-6f94-dd54-917b49bfacaa.gif)

## ノイズテクスチャを使って揺らす
ランダムな幅で揺らすと、どうしても鋭すぎる動きになってしまいます。
そこでノイズテクスチャを使って揺らします。

ノイズテクスチャとはおおよそ下の画像のような煙っぽい画像です。
![noise.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/e5ee08fa-6df5-8f5a-b64c-8c6aff05560f.png)

このテクスチャの指定の座標にある値を少しずつずらしながら取得すると、それなり値がランダムっぽい動きをして、それでいて滑らかに値が変化するため、ランダムの揺れのような激しさが緩和されます。

ランダムテクスチャを使用したスクリプトは以下のようになります、

```gd:Camera2D.gd
extends Camera2D

# ノイズテクスチャ
var noise := OpenSimplexNoise.new()
var noise_y := 0

# 揺れ時間
var time = 0

func shake():
	# 残り時間の幅でノイズテクスチャを使って揺らす
	noise_y += 1 # 動かす
	# 画面比率 (1024:60) 固定
	offset.x = 32    * time * noise.get_noise_2d(noise.seed * 2, noise_y)
	offset.y = 18.75 * time * noise.get_noise_2d(noise.seed * 3, noise_y)

func _ready():
	# 乱数初期化
	randomize()
	
	# ノイズテクスチャを生成
	noise.seed = randi()
	noise.period = 4
	noise.octaves = 2
	
	# カメラを画面の中心に移動 (解像度を 1024 x 600とした場合)
	position.x = 1024 / 2
	position.y = 600 / 2

func _process(delta):
	if time > 0:
		# 揺れ時間が残っていれば揺らす
		time = max(0, time - delta)
		shake()

	if Input.is_action_just_pressed("ui_accept"):
		# Spaceキーで揺れ開始
		time = 1 # 1秒
	
```

`OpenSimplexNoise` というのがノイズテクスチャを生成するモジュールです。

* [Docs » Godot API » OpenSimplexNoise -- Godot Engine](https://docs.godotengine.org/ja/stable/classes/class_opensimplexnoise.html)

実行すると以下のように、動きが滑らかなカメラ揺れとなります。

![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/73818d00-67ea-356c-2774-b49a32b3961c.gif)


# 参考

* [Screen Shake :: Godot Recipes](https://kidscancode.org/godot_recipes/2d/screen_shake/)