フォントの利用方法#

MGLは画面上に文字列を表示するための機能を提供しています。

MGLはゲームアプリケーションをターゲットとしたライブラリである性質上、様々な言語や書体に対応するためのカスタマイズを前提とした作りになっています。本項では、フォントの基本的な利用方法について解説します。

フォントとフォントリソース#

MGLにおけるフォントは、書体や表示方法を定義したフォントリソースと、それを操作するためのインターフェースクラスの2つを用いて扱います。この仕組みの概略図は次の通りです。

フォントシステムの概略図
../_images/font_system_diagram.svg

フォントリソースはMGL::Render::FontResourceを継承したクラスで、ここに使用するリソースの読み込みやレンダリング処理を定義します。フォントリソースは対となるフォントキーと共にフォントストレージへと登録し、以降はキーを指定して扱うことになります。

登録したフォントリソースを扱うためのクラスがMGL::Render::Fontクラスです。アプリケーションは基本的にこのクラスにフォントキーを与えて初期化し、それを用いて画面上への文字の表示を実現します。

フォントリソースはユーザー側で作成することを想定していますが、7ビットのASCIIコードに限定したビットマップフォントであれば、組み込みのMGL::Render::AsciiFontを利用可能です。本項ではこのフォントリソースクラスを利用して解説を進めていきます。

より多くの文字種を扱いたい場合はフォントリソースの作成(準備中)を参照して自作するか、ラスタライズフォント生成ツールの利用を検討してください。

フォントリソースの登録#

ここでは例として、MGLに標準で組み込まれているMGL::Render::AsciiFontクラスを利用して解説します。他のフォントリソースを用いる場合であっても、コンストラクタに指定する引数が異なる点を除いて、手順に違いはありません。

まず、MGL::Render::AsciiFontが扱うための画像データを用意します。このクラスが要求する画像データの要件は、「全ての文字の幅と高さがそれぞれ一致していること」と、「ASCIIコードの下位4ビットをX方向に、上位3ビットをY方向にずらした表になっていること」です。この条件を満たすASCIIコード表と、それを元に作成された8x8ドットフォント画像の例を次に示します。

ASCIIコード表
../_images/ascii_code.svg
8x8ドットフォント(128x128)
../_images/cbx_font8x8.png

注釈

ここでは見やすさのために背景をピンク色にしていますが、実際には透過色を設定します。また、この画像は実際にゲームに使用したものを引用しているため、一部の文字を別の文字に置き換えています。

注釈

書体が全体的に汚いのは当時の作者の画力の限界です。小文字はゲーム中ではほぼ使用していません。

フォントリソースを登録するためには、そのリソースを表すフォントキーも生成する必要があります。

フォントキーは一意の32ビット値で、ユーザーが任意の値を利用可能です。値の管理方法はユーザーに委ねられていますが、文字列のハッシュ値からフォントキーを生成するMGL::Render::MakeFontKeyを利用することも可能です。

文字列からフォントキーを生成する例
constexpr auto kAsciiFontKey = MGL::Render::MakeFontKey("ascii font");

フォントリソースを登録するには、MGL::Render::Font::Createを利用します。この関数はフォントリソースの生成と登録を同時に行うテンプレート関数です。この関数を用いて上記のフォントリソースを登録する例を次に示します。

8x8サイズのASCIIフォントを登録する例
// 登録処理
auto font = MGL::Render::Font::Create<MGL::Render::AsciiFont>(
    kAsciiFontKey,                      // フォントキーの指定
    "$resource/font_image.png", 8, 8);  // MGL::Font::AsciiFontのコンストラクタに送る引数

if (!font)
{
    // 登録失敗
}

テンプレート引数には登録したいクラスの型を指定し、第1引数にはフォントキーを、第2引数以降はフォントリソースクラスのコンストラクタに渡す引数を指定します。

MGL::Render::AsciiFontのコンストラクタの引数は、第1引数が読み込む画像ファイルのパス、第2引数が1文字あたりの幅、第3引数が1文字あたりの高さです。ここでは省略していますが、それ以降の引数指定により非同期読み込みや画像ファイル上のオフセットなども指定可能です。

登録に成功した場合、有効なフォントクラスが返ります。もし登録に失敗している場合は戻り値のフォントクラスが無効となるため、MGL::Render::Font::IsValidやbool型への変換により判別可能です。

使い終えたフォントリソースはMGL::Render::Font::Removeにて登録解除を行えます。フォントリソースの登録解除を行う例を次に示します。

// 登録解除
MGL::Render::Font::Remove(kAsciiFontKey);

引数には登録解除を行うフォントキーを指定します。ここでは先述の例で利用したASCIIフォントのキーを指定しています。フォントキーに対応したフォントリソースが存在しない場合は、この関数は何も行いません。

登録解除を行ったフォントリソースは、その時点でフォントキーによる取得が不可能となります。既に取得済みのフォントリソースは継続して利用可能です。フォントリソースクラスのデストラクタが呼び出されるタイミングは、そのリソースを利用している全てのフォントクラスの寿命が切れた時点となります。

注釈

2D描画にて解説しているテクスチャリソースと同様に、フォントリソースもまた参照カウント方式の共有リソースです。

フォントリソースはMGLが扱う他のリソースと同様に、アプリケーション終了時に自動で解放されます。したがって、アプリケーション動作中に常駐するフォントリソースに対しては、明示的に登録解除を行う必要はありません。

登録したフォントの利用方法#

登録済みのフォントを利用するためにはMGL::Render::Fontクラスを利用します。

このクラスはコンストラクタにフォントキーを指定することで、そのキーに対応したフォントリソースを取得します。既に解説したASCIIフォントを取得して初期化する例を次に示します。

フォントキーを指定してフォントクラスを初期化
MGL::Render::Font font(kAsciiFontKey);

if (!font)
{
    // キーに対応するリソースが登録されていない
}

初期化後にフォントクラスが有効な状態であれば、そのフォントを利用可能です。実際の利用例を次に示します。

フォントクラスを用いた文字表示の例
// 画面を黒でクリア
MGL::Render::Renderer2D renderer;
renderer.Clear(MGL::kColorBlack);

// フォントの取得
MGL::Render::Font font(kFontKey);
if (font)
{
    // 表示位置の設定(50, 50)
    font.SetPosition(MGL::Vector2(50.0f, 50.0f));

    // 文字の表示
    font.Print("Hello, MGL");
}
実行結果(640x480)
../_images/font_hello_mgl.png

画面のクリア等は2D描画を参照してください。

MGL::Render::Font::SetPositionにて表示位置を指定し、MGL::Render::Font::Printで表示文字列を指定します。表示文字列は整形機能も利用可能です。整形機能の詳細についてはテキスト整形を参照してください。

注釈

表示位置の座標の原点はMGL側では規定しておらず、フォントリソース側の実装に依存しています。これは、書体や言語によって文字の原点の位置が異なるためです。例えば、本項の例のような固定サイズのビットマップフォントでは文字の左上を原点とする事が多く、アウトラインフォントではベースラインの位置に原点を置くことが一般的です。

フォントクラスには様々なオプションを指定可能です。いくつかのオプションを指定して表示する例を次に示します。

フォントクラスのオプション利用例
// 画面を黒でクリア
MGL::Render::Renderer2D renderer;
renderer.Clear(MGL::kColorBlack);

// 目印に中央縦に赤線を表示
renderer.DrawLine(MGL::Vector2(320.0f, 0.0f), MGL::Vector2(320.0f, 480.0f), MGL::kColorRed);

// フォントの取得
MGL::Render::Font font(kFontKey);
if (font)
{
    // 表示位置の設定(50, 50)
    font.SetPosition(MGL::Vector2(50.0f, 50.0f));

    // 文字の表示
    font.Print("HELLO, MGL\n");

    // スケール値を2倍に設定して表示
    font.SetScale(MGL::Vector2(2.0f, 2.0f));
    font.Print("HELLO, MGL (SCALE = 2.0)\n");

    // マスクカラーを適用して表示
    font.SetMaskColor(MGL::kColorRed);
    font.Print("HELLO, MGL (COLOR = RED)\n");

    // 2ピクセルの文字間を設定して表示
    font.SetMargin(MGL::Vector2(2.0f, 0.0f));
    font.Print("HELLO, MGL (MARGIN X = 2)\n");

    // 表示位置を画面中央に移動(ついでに色と行間も設定)
    font.SetPosition(MGL::Vector2(320.0f, 240.0f));
    font.SetMargin(MGL::Vector2(0.0f, 4.0f));
    font.SetMaskColor(MGL::kColorWhite);

    // 左寄せ
    font.SetHorizontalAlignment(MGL::Alignment::Horizontal::Left);
    font.Print("LEFT ALIGNMENT\n");

    // 中央揃え
    font.SetHorizontalAlignment(MGL::Alignment::Horizontal::Center);
    font.Print("CENTER ALIGNMNET\n");

    // 右寄せ
    font.SetHorizontalAlignment(MGL::Alignment::Horizontal::Right);
    font.Print("RIGHT ALIGNMENT\n");
}
実行結果(640x480)
../_images/font_usage_options.png

その他のフォントオプションについては、MGL::Render::FontのAPIリファレンスを参照してください。

タグによるテキスト装飾#

MGL::Render::IndexedFontResourceを継承して作成したフォントリソースは、タグを使用することでテキストを装飾する機能を備えています。この機能は標準構成に含まれるMGL::Render::AsciiFontや、ラスタライズフォント生成ツール向けのエクステンションでも利用可能です。

使用するフォントがタグに対応しているかの判別はMGL::Render::Font::IsEnabledにて行えます。引数にMGL::Render::FontFeature::Tagを指定し、その戻り値を評価してください。

注釈

有効なタグの機能はフォントリソースによっても異なります。ここで示す例は、ラスタライズフォント生成ツールによって生成されたフォントリソースを用います。

共通#

タグはテキスト中に<>で囲んで記述し、<の次の文字によって制御が決定されます。テキスト中で<をそのまま表示したい場合は、<<と連続で記述することによってエスケープされます。

制御に使用する文字とその内容は次の通りです。

制御文字一覧

文字

制御内容

#

色の変更

$

書体の変更

@

振り仮名(ルビ)

/

タグのリセット

色の変更#

制御文字#はテキストの色を変更します。

<#red>のように、#の後にMGL::XColorで定義された名前で色を指定します。色の名前は数値以外は全て小文字で記述する必要があります。

変更した色を元に戻すにはリセットタグ</#>または</>を使用してください。

この制御はMGL::Render::Font::SetMaskColorで指定可能なマスクカラーを一時的に変更する動作になります。このため、テキスト全体の色を変更している場合でもタグによる色変更が優先されます。

利用例
MGL::Render::Font font(kFontKey);

if (font)
{
    font.SetPosition(MGL::Vector2(20.0f, 100.0f));
    font.Print("タグによる<#lime>色変え</>テスト\n");
    font.SetMaskColor(MGL::XColor::C215);
    font.Print("テキスト全体の色を変更しても<#red>タグに\nよる色変更が優先</>されます\n");
}
実行結果(640x480)
../_images/font_tag_color_change.png

書体の変更#

制御文字$はテキストの書体を変更します。現時点では、このタグは<$bold>(太字)にのみ対応しています。

変更した書体を元に戻すにはリセットタグ</$>または</>を使用してください。

このタグはフォントリソースが対応する書体を保持している場合にのみ使用できます。フォントが指定された書体を保持しているかの判別はMGL::Render::Font::HasFontFaceにて行えます。

利用例
MGL::Render::Font font(kFontKey);

if (font)
{
    font.SetPosition(MGL::Vector2(20.0f, 100.0f));

    if (font.HasFontFace(MGL::Render::FontFaceType::Bold))
    {
        font.Print("タグによる<$bold>太字</>テスト\n");
        font.Print("<#red><$bold>色変更との併用</>も可能\n");
    }
    else
    {
        font.Print("このフォントは太字に対応していません\n");
    }
}
実行結果(640x480)
../_images/font_tag_bold.png

振り仮名(ルビ)#

制御文字@は振り仮名(ルビ)を表示します。

<@親文字:ルビ文字>のように、':'または'='で区切って親文字とルビ文字を指定します。

ルビ文字の長さが親文字を超える場合、使用した区切り文字によって表示が変化します。':'を使用した場合はルビ文字の長さとは無関係に親文字を詰めて表示し、'='を使用した場合はルビ文字の長さに合わせて親文字の表示幅を調整して表示します。

このタグはフォントリソースがルビ用の書体を保持している場合にのみ使用できます。フォントがルビに対応しているかの判別はMGL::Render::Font::IsEnabledにて行えます。引数にMGL::Render::FontFeature::Rubyを指定し、その戻り値を評価してください。

利用例
MGL::Render::Font font(kFontKey);

if (font)
{
    font.SetPosition(MGL::Vector2(20.0f, 100.0f));
    font.SetMargin(MGL::Vector2(0.0f, 16.0f));

    if (font.IsEnabled(MGL::Render::FontFeature::Ruby))
    {
        font.Print("タグによる<@振り仮名:ルビ>テスト\n");
        font.Print("':'を使用:「<@画像:スクリーンショット>」\n");
        font.Print("'='を使用:「<@画像=スクリーンショット>」\n");
    }
    else
    {
        font.Print("このフォントはルビに対応していません\n");
    }
}
実行結果(640x480)
../_images/font_tag_ruby.png

タグのリセット#

制御文字/は、タグによって変更された設定を元に戻します。

</#></$>のように'/'の後に制御文字を記述することによって、その文字によって変更された設定をデフォルトの状態に戻します。</#$>のように複数同時に記述することも可能です。

</>のように制御文字を省略した場合、タグによる全ての変更をデフォルト状態に戻します。

利用例
MGL::Render::Font font(kFontKey);

if (font)
{
    font.SetPosition(MGL::Vector2(20.0f, 100.0f));
    font.Print("<#lime><$bold>太字+色変え\n"
               "</#>太字のみ(色変えリセット)\n"
               "</$>通常(太字リセット)");
}
実行結果(640x480)
../_images/font_tag_reset.png