【Godot】ゲームを一時停止するポップアップウィンドウの実装方法

# 概要
この記事では、ゲームを一時停止するポップアップウィンドウを実装します。

# 最も簡単なポップアップウィンドウ
`OS.alert()` と書くとゲームを止めて、ウィンドウがポップアップ表示されます。

```gd
OS.alert("メッセージウィンドウ", "")
```

![スクリーンショット_2021_02_11_0_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/15cf8653-6d40-4f03-2e5e-dfee93018959.png)

ただこれでは見栄えが良くないので、あくまでテスト用ですね。

ゲームを止めるには `get_tree().paused` に `true` を指定すると、ゲーム全体が停止します。ただ全部止まってしまうと解除できないので、ポップアップウィンドウはこの停止を無効にする設定をしておき、ウィンドウが閉じたら一時停止を解除する……という流れになるようにします。

# 動き回るオブジェクトを作成する
ゲームが一時停止されていることを確認するため、画面を動き回るオブジェクトを作ります。

例えば、`Area2D` ノード（シーン）を作成してスクリプトを以下のように記述します。

```gd:MovingObj
extends Node2D

var velocity = Vector2(200, 100)

func _ready():
	pass

func _process(delta):
	position += velocity * delta
	if position.x < 0:
		position.x = 0
		velocity.x *= -1
	if position.y < 0:
		position.y = 0
		velocity.y *= -1
	if position.x > 480:
		position.x = 480
		velocity.x *= -1
	if position.y > 320:
		position.y = 320
		velocity.y *= -1

```

画面内を動き回ります。

![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/51b4683f-c224-ebad-6b74-a4f550136c50.gif)

# ポップアップウィンドウ(シーン)の作成
次にポップアップウィンドウ(シーン)を作成します。

ノード構成は以下のようにしました

```
Dialog (Popup): ポップアップ(シーン)
  +-- FadeBg (ColorRect): 暗転用の板
  +-- Label: メッセージテキスト
  +-- Button: OKボタン
```

![Godot_Engine_-_TestPopup_-_Dialog_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/7e1a0cc6-27a6-5084-39fa-fd4649e6d13b.png)

テスト用なので、テキスト内容やボタンテキストは最低限のものとなります。

![Godot_Engine_-_TestPopup_-_Dialog_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/445356cb-c996-10a8-ee94-214f577a4af0.png)

このポップアップウィンドウを一時停止させないようにするため、`Dialog` ノードの `Pause > Mode` を `Process` に変更しておきます。
![Godot_Engine_-_TestPopup_-_Dialog_tscn_____と_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/91ea8362-d2dd-2734-2cab-fd48ac11d4ca.png)

## ボタンクリックのスクリプト
Dialogノードにスクリプトをアタッチして以下のように記述します。

```gd:Dialog.gd
extends Popup

func _on_Button_pressed():
	# ボタンがクリックされたらインスタンスを消す
	queue_free()
```

ボタン(Button)の `pressed` シグナルに `_on_Button_pressed()` を接続しています。
ボタンクリック時は `hide()` で非表示にするか、`queue_free()` でインスタンスを削除するか、好みがわかれそうですが、今回は削除する方法としました。

# メインシーンからポップアップウィンドウを呼び出す。

Mainシーンを作成して、動き回るオブジェクトとボタンを配置します。
![Godot_Engine_-_TestPopup_-_Main_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/5db9cbd6-70e6-de97-2d24-781eb0b13644.png)

実行イメージです。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/552f7723-f2eb-c750-f1c1-c5a753750dfb.gif)

Mainシーンにスクリプトをアタッチして以下のように記述します。

```gd:Main.gd
extends Node2D

# ポップアップウィンドウをプリロード
var Popup = preload("res://Dialog.tscn")

func _on_Button_pressed():
	# ポップアップウィンドウ呼び出し
	var popup = Popup.instance()
	
	# ポーズ開始。ゲームを止める
	get_tree().paused = true
	add_child(popup)
	popup.show_modal(true)
	
	# popup終了時に "_resume()" を呼び出す
	popup.connect('tree_exited', self, '_resume')

func _resume():
	# ウィンドウを閉じたときのコールバック
	var tree = get_tree()
	if tree:
		# ポーズ解除
		tree.paused = false	
```

ボタンの `press()` シグナルに `_on_Button_pressed()` を接続しておきます。
![Godot_Engine_-_TestPopup_-_Main_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/1c2751d7-0f74-8065-9c60-476f32587450.png)

ポップアップウィンドウを閉じた場合に、"tree_exited" シグナルに "_resume()" を接続しています。
そして、"resume()" でポーズを解除するようにしています。

では実行して一時停止と解除ができることを確認します。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/e5f27df6-c2bd-0a01-e932-3ff47f60b56b.gif)


# 参考

* [GODOT DOCS >> その他 >> ゲームの一時停止](https://docs.godotengine.org/ja/stable/tutorials/misc/pausing_games.html)