文字の TextureRegion を取得して「大破」する

Siv3D Advent Calendar 2013, 8 日目の記事です。
今日は December 2013 で追加された機能の 1 つ、Font から指定した文字の TextureRegion を取得する機能を紹介します。

これまでの Font を使った文字描画では、文字単位での描画や変形をサポートしていませんでしたが、December 2013 で追加された Font::getTexture(wchar_t) メソッドを使うと、Font 内部で確保された Texture 上にある、指定した文字の TextureRegion にアクセスできます。

TextureRegion というのはあまり目にしないクラスですが、例えばよく使う以下のようなコードでも TextureRegion オブジェクトが作成されています。

# include <Siv3D.hpp>

void Main()
{
	const Texture texture(L"Example/Windmill.png");

	while (System::Update())
	{
		//texture(0, 0, 100, 100).draw() を分解

		const TextureRegion t = texture(0, 0, 100, 100);

		t.draw();
	}
}

このように、もとになる Texture があり、その一部分を切り抜いたものが TextureRegion です。

さっそく Font::getTexture(wchar_t) を使ったサンプルを見てみましょう。


# include <Siv3D.hpp>

void Main()
{
	const Font font(100);

	while (System::Update())
	{
		const TextureRegion t = font.getTexture(L'あ');

		t.mirror().draw();

		font.getTexture(L'い').rotate(0.6).draw(100, 200);

		font.getTexture(L'う').scale(1.0,0.5).draw(300, 150);

		font.getTexture(L'え').flip().draw(300, 300);
	}
}

文字ごとに自由な変形を適用できます。
ただし、元のフォントのサイズが小さい場合は拡大した際にドットが荒くなってしまうので注意してください。

さて、今回の機能を使って最近流行りのゲームの文句を真似てみました。
結果画像がこれです。

# include <Siv3D.hpp>

void Main()
{
	Window::ShowCursor(false);

	const Font font(72, L"MS 明朝");

	const Color color(255, 101, 93);

	Graphics::SetBackground({ 150, 200, 220 });

	std::vector<Vec2> pts;

	for (int i = 0; i < 36; ++i)
	{
		pts.push_back(Circular(90 + (i % 2) * 20, TwoPi / 36 * i));
	}

	const Polygon back(pts);

	while (System::Update())
	{
		const Vec2 center = Mouse::Pos();

		const Vec2 taiPos = center - Vec2(50, 50);

		const Vec2 haPos = center + Vec2(55, 20);

		back.draw(center);

		back.drawFrame(center, 8.0, color);

		for (int i = 0; i < 16; ++i)
		{
			const Vec2 offset = Circular(5, TwoPi / 16 * i);

			font.getTexture(L'大').rotate(0.3).drawAt(taiPos + offset, Palette::Black);
		}

		font.getTexture(L'大').rotate(0.3).drawAt(taiPos, color);

		for (int i = 0; i < 16; ++i)
		{
			const Vec2 offset = Circular(5, TwoPi / 16 * i);

			font.getTexture(L'破').scale(0.8).rotate(0.3).drawAt(haPos + offset, Palette::Black);
		}

		font.getTexture(L'破').scale(0.8).rotate(0.3).drawAt(haPos, color);
	}
}