【Godot】Tweenの使い方

# 概要
この記事では、Godot Engine での Tween の使い方を説明します。

# Spriteの配置

Tweenで動かすオブジェクトとして、ここでは `Sprite` を使用します。
![Godot_Engine_-_TestTween.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/7f19afb2-78ac-1180-8ac5-56bcbb9446f2.png)

素材の画像は以下のものを使います。
![chabu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/2997b9b8-0aea-5c4b-8b98-05d76f60d8bd.png)

これを `Sprite > Texture` に割り当てます。
![Godot_Engine_-_TestTween_-_Sprite_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/ba950ab1-5368-6144-5c8e-172d6b151edd.png)

# Tweenノードを追加
`Sprite` ノードの下に `Tween` ノードをぶら下げます。
![Godot_Engine_-_TestTween_-_Sprite_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/4b17fd12-c163-db40-b176-1d4a1af654e3.png)
このような構成としました。
![Godot_Engine_-_TestTween_-_Sprite_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/0be37900-abea-3c13-4d37-fdb0e8a67fb7.png)

## スクリプトからTweenアニメーションを制御
`Sprite` ノードに対してスクリプトをアタッチして以下のように記述します

```gd:Sprite.gd
extends Sprite

func _ready():
	# Tweenノードを取得する
	var tween:Tween = $Tween
	
	# アニメーションパラメータを設定
	tween.interpolate_property(
		self,             # 自分自身を登録
		"position",       # positionパラメータを制御
		position,         # 開始座標は現在地
		Vector2(200, 64), # (200, 64)に移動
		1,                # 1秒間で移動
		Tween.TRANS_EXPO, Tween.EASE_OUT # ExpoOutで移動
	)
	
	# ループ設定
	tween.repeat = true # 1回再生して終わる場合は指定不要
	
	# 再生開始
	tween.start()
```

`Tween.interpolate_property()` がアニメーションパラメータの設定となります。
確認しやすいようにループ設定を有効にしていますが、これは通常は設定しなくても問題ありません

パラメータを設定したら、`Tween.start()` でアニメーションの再生を開始します。

実行するとアニメーションを確認できます。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/0523cb2e-b756-9661-4de3-22c357959c85.gif)

# Tweenノードをあらかじめ作らずにアニメーションを使う
Tweenノードを配置せずに、動的に生成してアニメーションすることも可能です。
その場合は以下のように記述します。

```gd:Sprite.gd
extends Sprite

func _ready():
	# Tweenノードを生成する
	var tween:Tween = Tween.new() # ①
	
	# アニメーションパラメータを設定
	tween.interpolate_property(
		self,             # 自分自身を登録
		"position",       # positionパラメータを制御
		position,         # 開始座標は現在地
		Vector2(200, 64), # (200, 64)に移動
		1,                # 1秒間で移動
		Tween.TRANS_EXPO, Tween.EASE_OUT # ExpoOutで移動
	)
	
	# ループ設定
	tween.repeat = true # 1回再生して終わる場合は指定不要
	
	# ②どこかのノードにぶら下げる必要がある
	add_child(tween)
	
	# 再生開始
	tween.start()
```

変更点は二箇所です。`var tween:Tween = Tween.new()` でインスタンスを生成し、**Tween.start() を呼び出す前** に、`add_child()` でシーンに追加します

# パラメータ指定の注意点
アニメーションに指定可能なパラメータですが、オブジェクト直下のパラメータのみとなります。
そのため以下の指定だとうまく動作しません。

```gd
	# ■X座標のみアニメーションしたい
	# アニメーションパラメータを設定
	tween.interpolate_property(
		self,             # 自分自身を登録
		"position.x",     # positionパラメータを制御
		position.x,       # 開始座標は現在地
		20,               # x=200に移動
		1,                # 1秒間で移動
		Tween.TRANS_EXPO, Tween.EASE_OUT # ExpoOutで移動
	)
```

X座標のみ動かしたい場合でも、Vector2を渡して制御する必要があります。

# カーブの種類について
カーブの種類は以下のものが指定可能です。

* TRANS_LINEAR
* TRANS_SINE
* TRANS_QUINT
* TRANS_QUART
* TRANS_QUAD
* TRANS_EXPO
* TRANS_ELASTIC
* TRANS_CUBIC
* TRANS_CIRC
* TRANS_BOUNCE
* TRANS_BACK

カーブの一覧は以下のページが参考になります。
https://easings.net/ja

たくさんあって使い道に悩みそうですが、個人的によく使うのは以下のものです。

* TRANS_LINEAR: 等速移動
* TRANS_EXPO: 急激なカーブ
* TRANS_ELASTIC: 激しく揺れる
* TRANS_CUBIC: 緩やかなカーブ
* TRANS_BOUNCE: バウンドする
* TRANS_BACK: 開始または終点を少しはみ出る


## TRANS_LINEAR: 等速直線移動
等速直線移動なので動きに面白みはないですが、目立たないアニメーションを行う場合に便利です
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/e0854534-5379-5fea-fb4e-4d2ef3bef4b9.gif)

## TRANS_EXPO: 急激なカーブ
![イージング関数チートシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/0ba77e81-4bd6-13e6-49b6-09920e0d7a32.png)

個人的に最もよく使うカーブです。メニューのUIにこれを適用して、各項目をずらしながら入場させると良い感じの動きとなります。
![picture_pc_e4ae1509978f49076a5ee1aa47015723.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/03c1f16d-5a03-2ec2-9317-11276a08dbeb.gif)

このカーブだと少し鋭すぎる場合には、TRANS_CUBIC が緩やかなカーブなのでおすすめです。
![イージング関数チートシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/4482cc0e-66ae-04bb-fa9f-77aa870420cd.png)

## TRANS_ELASTIC: 激しく揺れる
ELASTICは激しく揺れるカーブです。
![picture_pc_836dda81ef6ad06a93898069684d4d31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/bad2c380-66ed-a2fa-3b41-ea57f6a7451e.png)
拡大しながら表示されるオブジェクトに適用するとコミカルな感じの登場になります。

![picture_pc_5c67f13685246e743be3dd4801d5c339.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/da036fce-2f8e-bdcf-8b2b-3d923d8b9bd9.gif)

## TRANS_BOUNCE: バウンドする
TRANS_BOUNCEはバウンドする挙動です。
使い所はやや難しいですが、壁にぶつかったり落下しながら入場するようなUIに向いていると思います。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/a572e046-5d2a-e9a9-7ab0-9c4f77614f1a.gif)

## TRANS_BACK: 開始または終点を少しはみ出る
BACKは、少しはみ出るような動きとなります。
![picture_pc_94ceeee14289cbb3bf93cd2f98938048-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/c10fa65e-adeb-e6f4-fba1-57dcd8c37dc8.gif)

![picture_pc_052229ed1d1c9db4596df2cc72994ffd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/d8d342de-11b9-e620-6696-89a47f649857.png)



# IN/OUTと終了コールバックの設定方法
あと、IN/OUT の指定ですが、OUTは入場、INは退場する場合に使うのが、使いやすいと思います。

以下は、ExpoOutのアニメーションの終了時にコールバックでExpoInのアニメーションを行うコードです

```gd:Sprite.gd
extends Sprite

func _ready():
	
	# 開始を少し待つようにしてみる
	yield(get_tree().create_timer(2), "timeout")
	
	# Tweenノードを生成する
	var tween:Tween = Tween.new()
	
	# アニメーションパラメータを設定
	tween.interpolate_property(
		self,             # 自分自身を登録
		"position",       # positionパラメータを制御
		position,         # 開始座標は現在地
		Vector2(200, 64), # (200, 64)に移動
		1,                # 1秒間で移動
		Tween.TRANS_EXPO, Tween.EASE_OUT # ExpoOutで移動
	)
	
	# ループ設定
	#tween.repeat = true # 1回再生して終わる場合は指定不要
	
	# 終了時のコールバックを設定	
	tween.interpolate_callback(self, tween.get_runtime(), "tween_end")
	
	# どこかのノードにぶら下げる必要がある
	add_child(tween)
	
	# 再生開始
	tween.start()

func tween_end():
	# Tween終了時に呼び出されるコールバック
	# Tweenノードを生成
	var tween:Tween = Tween.new()
	
	# アニメーションパラメータを設定
	tween.interpolate_property(
		self,             # 自分自身を登録
		"position",       # positionパラメータを制御
		position,         # 開始座標は現在地
		Vector2(800, 64), # (800, 64)に移動
		1,                # 1秒間で移動
		Tween.TRANS_EXPO, Tween.EASE_IN # ExpoInで移動
	)
	add_child(tween)
	
	# 再生開始
	tween.start()
```

入場をOut、退場をInにすると良い感じのアニメーションとなります。

![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/e661e6a1-3283-17cc-a2eb-acc221357357.gif)


# 参考

* [GODOT DOCS » Godot API » Tween](https://docs.godotengine.org/ja/stable/classes/class_tween.html)