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

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

通知ボードを実装する

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

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

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

http://syun777.sakura.ne.jp/tmp/z_other/mplus-1c-regular.ttf_.zip

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

テーマリソースの作成

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

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

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を「1024x24」としました。

 

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回呼び出すたびに一番上に戻るようにしています。

 

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

 

 

完成プロジェクト

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

http://syun777.sakura.ne.jp/tmp/godot-data/NoticeBoard.zip

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