【Godot Engine】カスタムBBCodeタグの作り方【GDScript】
Godot Engine 4.3
はじめに
RichTextLabelノードではBBCodeタグを使用して多様なテキストエフェクトを実装できます。
デフォルトで用意されているタグだけでも大抵のことは実現できそうな感じですが、この記事では独自のBBCodeタグを作ってテキストエフェクトを作る方法を紹介します。
基本的な作り方
独自のBBCodeタグでテキストエフェクトを作るにはRichTextEffectクラスの_process_custom_fxメソッドをオーバーライドしてCharFXTransformクラスであるchar_fxのプロパティを変更することで実現可能となります。
_process_custom_fxはブール値を返す必要があり、テキストエフェクトを反映させるにはtrueを返す必要があります。逆にfalseが返されるとテキストに何も影響を与えなくなります。
また、BBCodeのタグ名はbbcodeという変数名で宣言される必要があります。
それでは単純なテキストエフェクトから作ってみましょう。
ここではテキストを黄色にハイライトするだけのBBCodeタグhighlightを作ります。
手順は以下の通りです。
- リソースの新規作成で
RichTextEffectを選択。ここではcustom_bbcode.tresとする - スクリプトの新規作成。ここでは
custom_bbcode.gdとする。コードは以下の通り
extends RichTextEffect
var bbcode := "highlight"
func _process_custom_fx(char_fx: CharFXTransform) -> bool:
char_fx.color = Color.GOLD
return true
-
custom_bbcode.tresのインスペクタからScriptにcustom_bbcode.gdをアタッチ

-
RichTextLabelノードのMarkUp->CustomEffectsにcustom_bbcode.tresを追加

基本的な手順は以上です。
あとはRichTextLabelノードのBBCode Enabledをオンにして試してみましょう。
Hello [highlight]Godot[/highlight] Engine
↓

それっぽいものを作る
もう少しテキストエフェクトらしいものを作ってみましょう。
ここでは次のようにテキストをt秒間隔で1文字ずつ表示させるBBCodeタグtw_charを作ります。
Tweenでvisible_charactersを補間するイメージです。
Hello [tw_char tick=0.5]Godot[/tw_char] Engine
↓

引数はchar_fx.envからDictionaryとして取得できます。
getメソッドは引数が与えられなくてもデフォルトの値を受け取ることができて便利なので活用しましょう。
スクリプトは以下の通りです。
extends RichTextEffect
var bbcode := "tw_char"
func _process_custom_fx(char_fx: CharFXTransform) -> bool:
char_fx.color.a = 0.0
var env: Dictionary = char_fx.env
var tick: float = env.get("tick", 1.0)
if is_equal_approx(tick, 0.0):
return false
var visible_char_count := int(char_fx.elapsed_time / tick)
if char_fx.relative_index < visible_char_count:
char_fx.color.a = 1.0
return true
このように独自のテキストエフェクトを実装するのに必要なプロパティは揃っていますので、公式ドキュメントの方も参考にしてみてください。
また、BBCodeは入れ子にすることもできます。入れ子にするにはBBCodeごとにリソースを作成してCustomEffectsに追加していきます。
Hello [tw_char tick=0.5][highlight]Godot[/highlight][/tw_char] Engine
↓

char_fxのプロパティについて個人的メモ
手を動かして分かった範囲でメモしておきます。公式ドキュメントも併せて参考に。
| プロパティ | 型 | メモ |
|---|---|---|
| env | Dictionary | 引数を取得できる。引数を文字列として受け取る場合、空白があってはならない(クォーテーションで囲まれていても)。受け取った値は形式に応じて型変換される。getメソッドを活用するのがよい |
| color | Color | 色 |
| elapsed_time | float | 経過時間。単位は秒 |
| font | RID | フォントのRID。フォントの変更もできるはず... |
| glyph_count | int | 書記素クラスタのグリフ数。例えば🇯🇵はU+1F1EFとU+1F1F5からなるなので2 |
| glyph_flag | int | 文字の種別判定。空白なのか、タブ文字なのかといったことなどを判別可能 |
| glyph_index | int | グリフのインデックス。フォントによって異なる。デフォルトのフォントだとaが68でbが69 |
| offset | Vector2 | 文字の描画位置に対するオフセット。文字の位置をずらしたいときに変更する |
| outline | bool |
trueならFX Transformはアウトラインの描画に呼び出されている...とのこと。アウトラインの有無に関わらずtrueとfalseが返されるのでよくわからない... |
| range | Vector2i | 文字の範囲。例えば[test]abc[/test]ならabcの範囲はそれぞれ(0, 1),(1, 2),(2, 3)であり123[test]abc[/test]ならabcは (3, 4),(4, 5),(5, 6)
|
| relative_index | int | 文字の相対的なインデックス。123[test]abc[/test]ならaが0 |
| transform | Transform2D | デフォルト値はTransform2D(1, 0, 0, 1, 0, 0) つまり transform.x == Vector2(1, 0)transform.y == Vector2(0, 1)transform.origin == Vector2(0, 0)ということ。いろいろ応用できそう... |
| visible | bool |
trueで文字を表示。falseなら非表示 |
Discussion