【ゲーム制作】DirectXでフォントを読み込んで表示する方法|DirectXTKで文字を出す

DirectXでフォントを読み込んで文字を表示するイメージ ゲーム制作

今回は、ゲーム制作でつまずきやすい「DirectXでフォントを読み込んで文字を表示する方法」について解説していきます。

「スコアや『GAME OVER』の文字を画面に出したい」
「DirectXって、実は文字を描く機能が標準で無いの?」
「日本語を出したら全部『□(豆腐)』になった…」

こんな悩みはありませんか?

実はDirectX本体には、「文字をそのまま描く」機能はありません。DirectXがやってくれるのは三角形やテクスチャを描くことだけ。文字は「フォントを画像(テクスチャ)に変換して、その一部を貼り付ける」という形で表示します。

この記事では、Microsoft公式の補助ライブラリDirectX Tool Kit(DirectXTK)SpriteFont を使う、いちばん実用的な方法を解説します。読み終えると、フォント表示の仕組み・準備の流れ・実装コード・日本語対応・ハマりどころが分かるようになりますので、ぜひ最後まで読んでください。

フォント表示の仕組み|文字は「画像の貼り付け」

DirectXでの文字表示は、次の2段階で考えると分かりやすいです。

  • 準備(事前)… フォントの各文字を1枚のテクスチャ(文字の集合画像)に焼き込み、「どの文字がどこにあるか」の情報も作る
  • 実行時… 文字列を1文字ずつ見て、対応する部分をスプライト(2D画像)として画面に貼る

つまり文字表示はテクスチャの切り貼りです。この「文字を焼き込んだ画像」をフォントアトラスと呼びます。DirectXTKは、この面倒な仕組みをまるごと肩代わりしてくれます。テクスチャの扱いは画像フォーマットの記事も参考になります。

準備|MakeSpriteFontで .spritefont を作る

DirectXTKには MakeSpriteFont というコマンドラインツールが付いています。これで、フォントを .spritefont という専用ファイル(アトラス+文字情報)に変換します。これは事前に1回やる作業です。

# インストール済みフォント名を指定して変換(英数字用)
MakeSpriteFont "Consolas" font.spritefont /FontSize:32

# TrueTypeファイルを直接指定することもできる
MakeSpriteFont "C:fontsmyfont.ttf" font.spritefont /FontSize:32

できあがった font.spritefont を、プログラムから読み込みます。exeと同じフォルダに置く(出力先へコピーする)のを忘れないようにしましょう。

実装|SpriteFontとSpriteBatchで描く

実行時に使うのは SpriteFont(フォント)と SpriteBatch(2D描画)の2つです。初期化はこれだけです。

#include <SpriteBatch.h>
#include <SpriteFont.h>
using namespace DirectX;

std::unique_ptr<SpriteBatch> spriteBatch;
std::unique_ptr<SpriteFont>  spriteFont;

// 初期化(device: ID3D11Device*, context: ID3D11DeviceContext*)
spriteBatch = std::make_unique<SpriteBatch>(context);
spriteFont  = std::make_unique<SpriteFont>(device, L"font.spritefont");

描画は、BeginEnd で挙んで DrawString を呼ぶだけです。文字列はワイド文字列(L"..."で渡します(ここは文字列リテラルのLの記事とつながります)。

// 毎フレームの描画処理の中で
spriteBatch->Begin();

spriteFont->DrawString(spriteBatch.get(),
    L"SCORE: 1200",              // 表示する文字列(ワイド文字)
    XMFLOAT2(100, 80),           // 表示位置(ピクセル)
    Colors::White);              // 色

spriteBatch->End();

たったこれだけで、画面に文字が出ます。位置・色に加えて、回転・拡大・原点なども DrawString の引数で指定できます。文字の幅を測る MeasureString を使えば、中央寄せや右寄せも簡単です。

日本語を表示する|文字の範囲を指定する

MakeSpriteFont は、指定しないと ASCII の 32(スペース)〜126(~)しかアトラスに含めません。日本語を出すには、/CharacterRegion使いたい文字コードの範囲を指定し、日本語グリフを持つフォント(メイリオ等)を使います。/CharacterRegion複数回くり返して指定できます

# ASCII + ひらがな + カタカナ を含める
MakeSpriteFont "メイリオ" jp.spritefont /FontSize:32 ^
  /CharacterRegion:0x20-0x7E ^
  /CharacterRegion:0x3040-0x309F ^
  /CharacterRegion:0x30A0-0x30FF

漢字まで全部入れるとアトラスが巨大になります。実務では「ゲームで実際に使う文字だけ」をテキストファイルにまとめて指定し、サイズを抑えるのが定番です。

他の方法との違い

  • DirectXTK(SpriteFont)…今回の方法。手軽でゲーム向き。初心者はまずこれ
  • DirectWrite + Direct2D…にじみのない高品質なUI文字向け。準備は多いが綺麗
  • ID3DXFont(D3DX9)…昔のDirectX9でよく使われたが、今は非推奨・入手困難。新規では使わない

【重要】私が日本語表示でハマった体験談

スコア表示はすぐできたのに、日本語のメッセージを出そうとしたら画面じゅうが「□□□□」(豆腐)だらけになりました。フォント名が悪いのかと、メイリオやMSゴシックに変えても直りません。

原因はMakeSpriteFontのCharacterRegion指定漏れでした。ASCIIしかアトラスに焼いていなかったので、ひらがな・漢字が「該当なし」で豆腐になっていたんです。/CharacterRegion でひらがな・カタカナの範囲を足したら、あっさり日本語が出ました。

「文字が□になる=アトラスにその文字が入っていない」と切り分けられるようになってから、フォント周りで悩まなくなりました。

DirectXフォント表示のよくある失敗例と対処法

①日本語が□(豆腐)になる

体験談のとおり、CharacterRegionに日本語の範囲を含めていないか、元フォントに日本語グリフが無いのが原因です。範囲指定と日本語対応フォントを使いましょう。なお /DefaultCharacter を指定すると、アトラスに無い文字の代わりに表示する文字を決められます。

②.spritefontが実行時に見つからない

読み込みで落ちるパターンです。.spritefontexeと同じ出力フォルダにコピーされるよう、プロジェクトの設定(ビルド後イベントや「出力ディレクトリにコピー」)を確認します。

③テキストの後に3D描画が乱れる

SpriteBatch は2D描画用にブレンドや深度などの描画ステートを設定します。そのため、テキストを描いたあとに3Dを描くと設定が食い違うことがあります。テキストは3D描画のあと(一番最後)に描くか、描画後に必要なステートを設定し直すと安定します。

注意点

  • フォント変換(MakeSpriteFont)は事前作業。実行時に毎回やるものではない
  • 文字列はワイド文字(L"..."wchar_tで渡す
  • テキストは2Dなので最後に描くとステート事故を避けやすい

まとめ

  • DirectX本体に文字描画は無く、フォントを画像にして貼るのが基本
  • DirectXTKのMakeSpriteFontで.spritefontを作り、SpriteFont+SpriteBatchで描く
  • 日本語はCharacterRegionで範囲指定+日本語フォントが必須
  • ハマりどころは豆腐・ファイルのコピー漏れ・描画ステート

文字が出せると、スコアやメニュー、セリフなど一気にゲームらしくなります。まずは英数字のスコア表示から始めて、次に日本語へ広げてみてください。

関連記事