文字を描画する前に、フォントが必要です。
文字を表示するソフトウェアなら SFML に限らず、みんなそうですね。
フォントを使う機能は sf::Font クラスにまとめられてます。
主に3つの機能があるよ。
「フォントをロードする」「グリフ(文字の見た目)を取得する」「属性を取得する」
普通のプログラムなら最初の「フォントをロードする」だけしか使わなくていいと思うから、まずはその機能に注目だ。
loadFromFile関数で、ハードディスク上のフォントファイルからフォントを読み込めます。
sf::Font font;
if (!font.loadFromFile ("arial.ttf") )
{
// error...
}
注意点。
SFMLはキミのマシンに入ってるシステムフォントを自動的に読み込んでくれるわけじゃないよ。
だから たとえば、font.loadFromFile ("Courier New") みたいにフォント名を指定してもダメです。
理由は2つ。まず SFMLさんは「ファイル名」を知りたがってます。「フォント名」じゃダメなのです。
そして、SFML には、キミのマシンのどのフォルダにシステムフォントが入っているのか知る由もないのです。
そんなわけで、フォントを読み込むときは、フォントのファイルが必要だよ。
たとえば画像を表示するには画像ファイルが必要だよね? それと同じようなものだと思ってね。
この loadFromFile関数なんだけど、ときどき、よくわかんない理由で失敗してしまいます。
そんなときは、まず、エラーメッセージをチェックせよ。コンソールに出力されてます。
さて、なんて言ってるでしょう? 「unable to open file」? そんなときは、カレントディレクトリを確認だ。
カレントディレクトリっていうのは、キミのアプリケーションがファイルを読み込むときの、
相対パスの出発点になるフォルダのことです。 さて、キミの思ってる通りのフォルダかな?
アプリケーションをデスクトップ環境で起動しているときは、
そのアプリケーションが置いてあるフォルダがカレントディレクトリなのだけど、
IDE(Visual Studio とか、Code::Blocksとか)から起動してるときは、
そのプロジェクトのフォルダになってるかも。プロジェクトの設定でカンタンに変更できるはず。
訳注:「スプライトとテクスチャ」の loadFromFileに関する注意書きと同じ文面です(原文が)。
そのほか、メモリからフォントを読み込むこともできます(loadFromMemory関数)。
ストリームからも読み込めます(loadFromStream関数)。
どんなフォントのフォーマットが使えるかというと、大体みんなが知ってるフォーマットは使えます。
APIドキュメントに一覧があるので、よかったら見てみてね。
読み込み方法は以上です。
フォントを読み込んだら、いよいよ文字を表示できるよ!
文字を表示するには、sf::Textクラスを使います。
使い方はすごくカンタン:
sf::Text text;
// select the font
text.setFont (font); // font の型は sf::Font です。
// 表示したい文字を設定
text.setString ("ABCDEFG");
// 文字のサイズを設定
text.setCharacterSize (24); // 単位はピクセル。ポイントじゃないよ!
// 色を設定
text.setColor (sf::Color::Blue);
// スタイルを設定
text.setStyle (sf::Text::Bold | sf::Text::Underlined);
...
//表示。メインループ内の、window.clear() と window.display()の間で。
window.draw(text);
表示位置・向き・倍率も設定できます。
やり方は sf::Sprite や、SFML の他の物体と同じなので、詳しくは
位置、回転、拡大のページでおはなしするよー。
非ASCII文字 (アクセント記号つき欧州文字、アラビック、漢字、など) を正しく扱うのは、ちょっとややこしいです。
いろいろなエンコードについて、どんなふうに文字が表示されるのか、仕組みを詳しく知ってる必要があります。
そのへんの面倒な話を避けて通るには、ワイド文字列のリテラルを使うとよいです。
text.setString ( L"éèàç" );
文字列の前の "L" ってのがミソですね! コンパイラに、ワイド文字列を生成するように伝えてます。
ワイド文字列ってのは C++ のストレンジビーストで、標準仕様ではサイズについて何も言ってません(16bit? 32bit?)
どんなエンコードが使われてるのかも語られてません(UTF-16? UTF-32?)
とは言え、大体の OS でどうなってるのかはわかってます。
必ずというわけではないけど、Unicode文字列が生成されてます。そんでもって、SFML はその扱い方を心得てます。
さて注意点。
C++11 の仕様では、UTF-8、UTF-16、UTF-32 のリテラル文字列を扱うための、
新たな文字列型とプレフィックスがサポートされてるのですが、SFMLでは、まだサポートされてません。
それと、表示したい文字が、読み込んだフォントの中に含まれてるかどうかも一応気をつけてね。
全部の文字が含まれてるわけじゃないからね(Unicodeの標準フォントの中には 100000文字以上もあるよ!)。
たとえばアラビック文字のフォントでは日本語は表示できないよね。
もし sf::Textクラスが使いにくいとか、デフォルトのグリフ以外を使いたいときには、
sf::Fontクラスを使うと、もっといろいろとできるよ。
文字サイズを指定して、そのフォントに含まれている文字が描かれたテクスチャを生成します。
const sf::Texture& texture = font.getTexture(characterSize);
ただし、グリフ(文字の形)が実際にテクスチャに書き込まれるのは、リクエストがあったとき、です。
文字の数はすごく多いので(100000以上、ね)フォントをロードした時点で全部を生成するのは無理なのです。
getGlyph関数を呼んだ時点で、大急ぎでレンダリングされます(下記参照)。
グリフを書き込んだテクスチャを使いこなすには、
テクスチャの中のどの位置にある文字(グリフ)を使いたいのか、その座標を取得する必要があります。
sf::Glyph glyph = font.getGlyph(character, characterSize, bold);
上のサンプルの "character" がキミが表示したい文字です。UTF-32 のコードで指定します。
それと、文字のサイズと、太字(bold)にするかどうかを指定します。
sf::Glyph構造体には、3つのメンバーが入ってます。
- textureRect:テクスチャの中のどこにこの文字(グリフ)があるか? の座標
- bounds:このグリフを囲んでいる四角形。表示位置をベースラインに合わせるときに役立ちます。
- advance:隣の文字への横方向の距離
では最後に、
行間やカーニング(飾りひげ)といった、他の寸法を取得する方法です。
(基本的に、文字のサイズによって決まります)
int lineSpacing = font.getLineSpacing (characterSize);
int kerning = font.getKerning(character1, character2, characterSize);