【Godot】デバッグ時に役立つ「通知ボード」の実装方法

今回はデバッグ時に役立つ「通知ボード」の実装方法について紹介します。

通知ボードを実装する

今回紹介する「通知ボード」とは、画面の一部分にデバッグメッセージを表示するものです。
print() でもデバッグ用のメッセージを出力できますが、ちょっとした警告・エラーメッセージであれば画面内に表示したほうが気が付きやすいので、そういった場合に使えるのかと思います。

フォントデータのダウンロード

今回使用するフォントデータをダウンロードします。

ダウンロードしたフォントデータをプロジェクトに追加します。

テーマリソースの作成

次にフォントデータを利用するためのテーマリソースを作成します。

ファイルシステムで右クリックして「新規リソース」を選びます。

Themeを選んで「作成」をクリックします。

「保存」を選びます。

インスペクターから「Default Font > [空]」をクリックして「新規 DynamicFont」を選びます。

作成した Dynamic Font をクリックするとフォント設定が表示されるので「Font > Font Data > [空]」をクリックして、「新規 DynamicFontData」を選びます。

作成した 新規 DynamicFontData をクリックして「Font Path」のところにあるフォルダアイコンをクリックします。

設定したフォントにアウトライン(縁取り)をつけるために「Settings > Outline Size」を「1」にして「Outline Color」を黒色にします。

するとエディタの下部分に表示されているテーマのプレビュー画面に縁取りされたフォントが表示されます。

表示されていなかったり小さくてよくわからない場合は Settings > Size を変更すると大きくしたり表示が更新されます。

今回は文字サイズを「16pt」とするので「16」にしておきます。

最後にテーマビューの「保存」を押して保存します。

特にこのボタンは押さなくても自動保存されるようですが、念のため押しておきます。

通知ボードオブジェクトの作成

ノードの作成

次にNode2Dを作成して名前を「NoticeBoard」に変更します。

ファイルシステムで右クリックして「新規リソース」を選びます。

次に「ColorRect」「Label」の順でノードを作成します。

,ノード階層は以下のようになります。

まず Label ノードの Text に「デバッグメッセージ」と入力しておきます。

 ただテーマが設定されていないので文字が表示されません。

ラベルにテーマを設定する

「Control > Theme > [空]」をクリックして「読み込み」を選びます。

先ほど作成した「new_theme.tres」を読み込みます。

するとこのように文字が表示されるようになりました。

背景のサイズと色を設定する

次に ColorRect を選んでサイズを調整します。

インスペクタから Position > x を「-8」、Sizeを「1024×24」としました。

Positionのxを左にずらしているのは余白にゆとりを持たせるためで、サイズは画面サイズの幅がデフォルトで 1024 となっており、高さについてはフォント16ptだと 24px くらいがちょうど良いためです。

このあたりは好みで設定して問題ないと思います。

次に「Color」のA (アルファ値) を 「80」にしておきます。

この値も好みで良いと思います。

スクリプトのアタッチ

これでUIの部品は設定できたのでスクリプトを作成します。

NoticeBoardノードを選んでスクリプトをアタッチします。

extends Node2D

const MARGIN_X = 8
const START_X = 1024+MARGIN_X # 開始座標
const MIN_W = 240 # 最小の幅

# 状態
enum eState {
	IN, # 入場
	WAIT, # 少し待つ
	OUT, # 退場
}

var _state = eState.IN # 状態
var _timer := 0.0 # タイマー

onready var bg = $ColorRect
onready var label = $Label

func _ready() -> void:
	# 開始位置を設定する
	position.x = START_X

func start(msg:String, color=Color.black) -> void:
	# 開始処理
	label.text = msg
	bg.modulate = color

func _process(delta: float) -> void:
	_timer += delta
	
	# メッセージの横幅を求める
	var font = label.get_theme_default_font()
	var w = font.get_string_size(label.text).x
	# 最低保障の幅より大きければ拡張する
	w = max(w, MIN_W)
	w += MARGIN_X
	
	match _state:
		eState.IN: # 入場中
			position.x = START_X - w * _expo_out(_timer)
			if _timer > 1.0:
				# 少し待つ
				_state = eState.WAIT
				_timer = 0
		eState.WAIT: # 少し待つ
			position.x = START_X - w
			if _timer > 3.0:
				# 退場する
				_state = eState.OUT
				_timer = 0
		eState.OUT: # 退場する
			position.x = START_X - w * (1.0 - _expo_out(_timer))
			if _timer > 1.0:
				# 終了
				queue_free()

func _expo_out(t):
	return -pow(2, -10*t) + 1

このオブジェクトは生成された後、start()関数でメッセージと色を設定します。

動きとしては、

開始時は左の外側にいて少しずつ入場します。(eState.IN)

そして入りきったら 3秒ほど停止します。(eState.WAIT)

そして左側へ退場して消滅します。(eState.OUT)

通知ボードを使用するシーンの作成

ではこの通知ボードオブジェクトを作成するテスト用のシーンを作成します。

Node2Dシーンを作成して名前を「Main」にリネームします。

そして以下のスクリプトをアタッチします。

extends Node2D

const NoticeBoard = preload("res://NoticeBoard.tscn")

var count = 0

func _process(delta: float) -> void:
	if Input.is_action_just_pressed("ui_accept"):
		# ランダムで表示するメッセージ
		var msg_tbl = [
			"デバッグメッセージ",
			"警告メッセージ",
			"エラーメッセージ",
		]
		
		# ランダムで変化する色
		var color_tbl = [
			Color.black,
			Color.yellow,
			Color.red
		]
		
		#var msg = _choice(msg_tbl)
		#var color = _choice(color_tbl)
		var rnd = randi()%3
		var msg = msg_tbl[rnd]
		msg += str(count)
		var color = color_tbl[rnd]
		
		# 通知ボードを表示する
		_add_notice(msg, color)

# リストから抽選を行う
func _choice(tbl):
	var length = tbl.size()
	var rnd = randi()%length
	return tbl[rnd]

# 通知ボードを生成する
func _add_notice(msg:String, color:Color = Color.black):
	var notice = NoticeBoard.instance()
	add_child(notice)
	notice.start(msg, color)
	# 生成数に応じてY座標を移動する
	notice.position.y = 24 * count

	# 生成数をカウントアップする
	count = (count + 1)%20

このスクリプトはスペースキーを押すと、ランダムな通知メッセージを表示するものです。

_add_notice() が実際に通知ボードを生成している関数です。

# 通知ボードを生成する
func _add_notice(msg:String, color:Color = Color.black):
	var notice = NoticeBoard.instance()
	add_child(notice)
	notice.start(msg, color)
	# 生成数に応じてY座標を移動する
	notice.position.y = 24 * count

	# 生成数をカウントアップする
	count = (count + 1)%20

変数「count」に生成した回数をカウントして、その値をもとに Y座標を下にずらしていきます。

そして20回呼び出すたびに一番上に戻るようにしています。

では実行して動作を確認します。

完成プロジェクト

今回作成したプロジェクトを添付しておきます。

入退場に1秒は長いような気がしたので 0.5 秒に変更しています。