はかせのラボ

私の頭の中を書いていく雑記ブログです

DirectX 文字列描画

あいさつ

牛のような遅さでも歩みを止めないことが
大事だと思ってるはかせです。
今回は前回実装した文字描画を改造して
文字列描画をできるようにしたので書きます。

そもそも文字列描画とは

文字列というのは極論を言えば1文字の連続です。
つまり1文字描画が出来ている以上文字列は描画できます。

ただ前回までのプログラムでは1文字ずつ指定して
描画しなければいけませんでした。
例えばscoreって出すのに
sを描画
cを描画
oを描画
rを描画
eを描画

こんな感じでやらなきゃいけなかったわけです。
ぶっちゃけめんどくさいです。
scoreって出したかったら

print(score)

このぐらいで出したいのです。

実装方法

結論から言うと1文字描画を渡された文字分やってるだけです。
さすがにこれで終わりだとあれなんでちょっと詳しく書きます。
まずは動画です。右下に注目です。
youtu.be

次にコードです。

//texts = 表示したい文字列

//呼び出し方
UpdateText(texts);

//文字数
auto size = wcslen(texts);
//文字の行間
auto offset = mGameObject->GetTransform()->Scale.x;
//自身が持っている1文字描画クラスのインスタンス数と表示したい文字数の差
auto addRendererNum = (int)(size - mRenderers.size());
//出そうとする文字数が自分の持っている1文字描画クラスのインスタンス数より多ければ
if(addRendererNum > 0)
{
	//不足分を追加する
	for(int i = 0;i < addRendererNum;i++)
	{
		auto renderer = mGameObject->AddComponent<TextRenderer>();
		mRenderers.push_back(renderer);
	}
}
//文字更新
for (int i = 0; i < size; i++)
{
	mRenderers[i]->CreateText(&texts[i], (float)i * offset);
}
//余ってるコンポーネントを空白にする
if(addRendererNum < 0)
{
	for (int i = size; i < size + abs((int)addRendererNum); i++)
	{
		mRenderers[i]->CreateText(L" ", (float)i * offset);
	}
}

こんな感じで表示したい文字列を1文字ずつに分解して
1文字表示クラスに流すことで文字列描画をしています。

そして表示クラスが足りなければ補充し、
逆に余れば空白を表示しています。

これだけなんですがこれを考えるのにすごい時間がかかりましたw
ネット上に文字の描画の仕方はそこそこ落ちてるんですが
文字列に関してはあまりなくて今日一日頭を悩ましてましたw

結果として
文字列=1文字の連続
という当たり前のことに気づき実装することが出来ました。

負荷的にも所詮は画像描画なのでそこまでかからないですし
いつもどおりテクスチャはキャッシュしてあるので(戒め)
メモリもそこまで問題になりません。

コードの整理は必要ですがそこそこ良さげな形に落とし込めた気がします。

今回作ったものはgithubに上げました
github.com