コンテンツにスキップ

2. ポップな UI の作成

2.1 ボタンの背景を RenderTexture で作る

  • ScopedRenderTarget2D を使うと、描画先を標準のシーンではなく、別のレンダーテクスチャに変更できます
  • レンダーテクスチャは RenderTextureMSRenderTexture があり、アンチエイリアシングが有効な後者を使うと画質が良いです
  • レンダーテクスチャは、通常の Texture のように使うことができます

# include <Siv3D.hpp>

// ボタンの背景テクスチャを作成する
Texture CreateButtonTexture()
{
	MSRenderTexture renderTexture{ Size{ 160, 60 }, ColorF{ 0.96 } };
	{
		const ScopedRenderTarget2D renderTarget{ renderTexture };

		const ColorF PatternColor{ 0.85 };

		for (int32 x = 0; x <= 8; ++x)
		{
			RectF{ Arg::center((x * 20), 25), 2 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 30), 3 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 35), 4 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 40), 5 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 45), 6 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 50), 7 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 55), 8 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 60), 9 }.rotated(45_deg).draw(PatternColor);
		}
	}

	// MSRenderTexture の完成には
	// 2D 描画命令の発行 (Flush) + MSAA の解決 (Resolve) が必要
	Graphics2D::Flush();
	renderTexture.resolve();

	// 完成したテクスチャを返す
	return renderTexture;
}

void Main()
{
	const Texture buttonTexture = CreateButtonTexture();

	while (System::Update())
	{
		buttonTexture.draw();
	}
}

2.2 RoundRect に貼り付ける

  • RoundRect にテクスチャを貼り付けて描画できます

# include <Siv3D.hpp>

// ボタンの背景テクスチャを作成する
Texture CreateButtonTexture()
{
	MSRenderTexture renderTexture{ Size{ 160, 60 }, ColorF{ 0.96 } };
	{
		const ScopedRenderTarget2D renderTarget{ renderTexture };

		const ColorF PatternColor{ 0.85 };

		for (int32 x = 0; x <= 8; ++x)
		{
			RectF{ Arg::center((x * 20), 25), 2 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 30), 3 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 35), 4 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 40), 5 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 45), 6 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 50), 7 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 55), 8 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 60), 9 }.rotated(45_deg).draw(PatternColor);
		}
	}

	// MSRenderTexture の完成には
	// 2D 描画命令の発行 (Flush) + MSAA の解決 (Resolve) が必要
	Graphics2D::Flush();
	renderTexture.resolve();

	// 完成したテクスチャを返す
	return renderTexture;
}

void Main()
{
	const Texture buttonTexture = CreateButtonTexture();

	const Rect rect{ 200, 300, buttonTexture.size() };

	const RoundRect roundRect{ rect, 10 };

	while (System::Update())
	{
		roundRect(buttonTexture).draw();
	}
}

2.3 テキストと絵文字を追加する

  • Rect::getRelativePoint(relativeX, relativeY) は、長方形の左上を (0 ,0), 右下を (1, 1) としたときの (relativeX, relativeY) の座標を返します

# include <Siv3D.hpp>

// ボタンの背景テクスチャを作成する
Texture CreateButtonTexture()
{
	MSRenderTexture renderTexture{ Size{ 160, 60 }, ColorF{ 0.96 } };
	{
		const ScopedRenderTarget2D renderTarget{ renderTexture };

		const ColorF PatternColor{ 0.85 };

		for (int32 x = 0; x <= 8; ++x)
		{
			RectF{ Arg::center((x * 20), 25), 2 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 30), 3 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 35), 4 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 40), 5 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 45), 6 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 50), 7 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 55), 8 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 60), 9 }.rotated(45_deg).draw(PatternColor);
		}
	}

	// MSRenderTexture の完成には
	// 2D 描画命令の発行 (Flush) + MSAA の解決 (Resolve) が必要
	Graphics2D::Flush();
	renderTexture.resolve();

	// 完成したテクスチャを返す
	return renderTexture;
}

void Main()
{
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

	const Texture buttonTexture = CreateButtonTexture();

	const Font font{ FontMethod::MSDF, 48, Typeface::Heavy };

	const Texture emoji{ U"🗺"_emoji };

	const Rect rect{ 200, 300, buttonTexture.size() };

	const RoundRect roundRect{ rect, 10 };

	const ColorF PrimaryColor{ 0.3, 0.5, 1.0 };

	while (System::Update())
	{
		roundRect(buttonTexture).draw();

		const Vec2 emojiCenter = rect.getRelativePoint(0.5, 0.05);

		emoji.scaled(0.4).drawAt(emojiCenter);

		font(U"マップ").drawAt(TextStyle::Outline(0.0, 0.2, ColorF{1.0}), 26, rect.getRelativePoint(0.5, 0.7), PrimaryColor);
	}
}

2.4 絵文字と同じポリゴンを作成する

  • Image::alphaToPolygonsCentered() は画像の非透過の部分からポリゴンの配列を作成します。

# include <Siv3D.hpp>

// ボタンの背景テクスチャを作成する
Texture CreateButtonTexture()
{
	MSRenderTexture renderTexture{ Size{ 160, 60 }, ColorF{ 0.96 } };
	{
		const ScopedRenderTarget2D renderTarget{ renderTexture };

		const ColorF PatternColor{ 0.85 };

		for (int32 x = 0; x <= 8; ++x)
		{
			RectF{ Arg::center((x * 20), 25), 2 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 30), 3 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 35), 4 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 40), 5 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 45), 6 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 50), 7 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 55), 8 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 60), 9 }.rotated(45_deg).draw(PatternColor);
		}
	}

	// MSRenderTexture の完成には
	// 2D 描画命令の発行 (Flush) + MSAA の解決 (Resolve) が必要
	Graphics2D::Flush();
	renderTexture.resolve();

	// 完成したテクスチャを返す
	return renderTexture;
}

MultiPolygon CreateEmojiPolygons(const Emoji& emoji)
{
	return Image{ emoji }.alphaToPolygonsCentered(160, AllowHoles::No);
}

void Main()
{
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

	const Texture buttonTexture = CreateButtonTexture();

	const Font font{ FontMethod::MSDF, 48, Typeface::Heavy };

	const Texture emoji{ U"🗺"_emoji };

	const Rect rect{ 200, 300, buttonTexture.size() };

	const RoundRect roundRect{ rect, 10 };

	const ColorF PrimaryColor{ 0.3, 0.5, 1.0 };

	const MultiPolygon polygons = CreateEmojiPolygons(U"🗺"_emoji).scaled(0.4);

	while (System::Update())
	{
		roundRect(buttonTexture).draw();

		const Vec2 emojiCenter = rect.getRelativePoint(0.5, 0.05);

		emoji.scaled(0.4).drawAt(emojiCenter);

		font(U"マップ").drawAt(TextStyle::Outline(0.0, 0.2, ColorF{1.0}), 26, rect.getRelativePoint(0.5, 0.7), PrimaryColor);

		polygons.draw(Cursor::Pos());
	}
}

2.5 絵文字に輪郭を付ける

  • Polygon::calculateRoundBuffer(x) でポリゴンを太らせることができます
  • 次のような関数をつくると、安定して絵文字を太らせることができます

# include <Siv3D.hpp>

// ボタンの背景テクスチャを作成する
Texture CreateButtonTexture()
{
	MSRenderTexture renderTexture{ Size{ 160, 60 }, ColorF{ 0.96 } };
	{
		const ScopedRenderTarget2D renderTarget{ renderTexture };

		const ColorF PatternColor{ 0.85 };

		for (int32 x = 0; x <= 8; ++x)
		{
			RectF{ Arg::center((x * 20), 25), 2 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 30), 3 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 35), 4 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 40), 5 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 45), 6 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 50), 7 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 55), 8 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 60), 9 }.rotated(45_deg).draw(PatternColor);
		}
	}

	// MSRenderTexture の完成には
	// 2D 描画命令の発行 (Flush) + MSAA の解決 (Resolve) が必要
	Graphics2D::Flush();
	renderTexture.resolve();

	// 完成したテクスチャを返す
	return renderTexture;
}

MultiPolygon CreateEmojiPolygons(const Emoji& emoji)
{
	return Image{ emoji }.alphaToPolygonsCentered(160, AllowHoles::No);
}

MultiPolygon MakeRoundBuffer(const MultiPolygon& polygons, int32 distance)
{
	MultiPolygon result;

	for (const auto& polygon : polygons)
	{
		result = Geometry2D::Or(result, polygon.calculateRoundBuffer(distance));
	}

	return result;
}

void Main()
{
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

	const Texture buttonTexture = CreateButtonTexture();

	const Font font{ FontMethod::MSDF, 48, Typeface::Heavy };

	const Texture emoji{ U"🗺"_emoji };

	const Rect rect{ 200, 300, buttonTexture.size() };

	const RoundRect roundRect{ rect, 10 };

	const ColorF PrimaryColor{ 0.3, 0.5, 1.0 };

	const MultiPolygon polygons = MakeRoundBuffer(CreateEmojiPolygons(U"🗺"_emoji), 4).scaled(0.4);

	while (System::Update())
	{
		roundRect(buttonTexture).draw();

		const Vec2 emojiCenter = rect.getRelativePoint(0.5, 0.05);

		polygons.draw(emojiCenter, ColorF{ 0.3, 0.25, 0.2 });

		emoji.scaled(0.4).drawAt(emojiCenter);

		font(U"マップ").drawAt(TextStyle::Outline(0.0, 0.2, ColorF{ 1.0 }), 26, rect.getRelativePoint(0.5, 0.7), PrimaryColor);
	}
}

2.6 マウスオーバーで絵文字を揺らす

# include <Siv3D.hpp>

// ボタンの背景テクスチャを作成する
Texture CreateButtonTexture()
{
	MSRenderTexture renderTexture{ Size{ 160, 60 }, ColorF{ 0.96 } };
	{
		const ScopedRenderTarget2D renderTarget{ renderTexture };

		const ColorF PatternColor{ 0.85 };

		for (int32 x = 0; x <= 8; ++x)
		{
			RectF{ Arg::center((x * 20), 25), 2 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 30), 3 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 35), 4 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 40), 5 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 45), 6 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 50), 7 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 55), 8 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 60), 9 }.rotated(45_deg).draw(PatternColor);
		}
	}

	// MSRenderTexture の完成には
	// 2D 描画命令の発行 (Flush) + MSAA の解決 (Resolve) が必要
	Graphics2D::Flush();
	renderTexture.resolve();

	// 完成したテクスチャを返す
	return renderTexture;
}

MultiPolygon CreateEmojiPolygons(const Emoji& emoji)
{
	return Image{ emoji }.alphaToPolygonsCentered(160, AllowHoles::No);
}

MultiPolygon MakeRoundBuffer(const MultiPolygon& polygons, int32 distance)
{
	MultiPolygon result;

	for (const auto& polygon : polygons)
	{
		result = Geometry2D::Or(result, polygon.calculateRoundBuffer(distance));
	}

	return result;
}

void Main()
{
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

	const Texture buttonTexture = CreateButtonTexture();

	const Font font{ FontMethod::MSDF, 48, Typeface::Heavy };

	const Texture emoji{ U"🗺"_emoji };

	const Rect rect{ 200, 300, buttonTexture.size() };

	const ColorF PrimaryColor{ 0.3, 0.5, 1.0 };

	const MultiPolygon polygons = MakeRoundBuffer(CreateEmojiPolygons(U"🗺"_emoji), 4).scaled(0.4);

	// .update(true) で 1.0 になるまでの時間, .update(false) で 0.0 になるまでの時間
	Transition transition{ 0.0s, 0.8s };

	while (System::Update())
	{
		const RoundRect roundRect{ rect, 10 };

		RoundRect{ rect, 10 }(buttonTexture).draw();

		const bool mouseOver = roundRect.mouseOver();

		// マウスカーソルがボタンの上に入ったときにトリガー
		transition.update((not roundRect.intersects(Cursor::PreviousPos())) && mouseOver);

		{
			const Vec2 emojiCenter = rect.getRelativePoint(0.5, 0.05);
			double angle = Math::Sin(transition.value() * 8_pi) * 6_deg * transition.value();

			{
				// emojiCenter を中心に angle だけ回転する座標変換
				const Transformer2D transformer{ Mat3x2::Rotate(angle, emojiCenter) };
				polygons.draw(emojiCenter, ColorF{ 0.3, 0.25, 0.2 });
				emoji.scaled(0.4).drawAt(emojiCenter);
			}
		}

		font(U"マップ").drawAt(TextStyle::Outline(0.0, 0.2, ColorF{ 1.0 }), 26, rect.getRelativePoint(0.5, 0.7), PrimaryColor);
	}
}

2.7 マウスオーバー時の色

# include <Siv3D.hpp>

// ボタンの背景テクスチャを作成する
Texture CreateButtonTexture()
{
	MSRenderTexture renderTexture{ Size{ 160, 60 }, ColorF{ 0.96 } };
	{
		const ScopedRenderTarget2D renderTarget{ renderTexture };

		const ColorF PatternColor{ 0.85 };

		for (int32 x = 0; x <= 8; ++x)
		{
			RectF{ Arg::center((x * 20), 25), 2 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 30), 3 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 35), 4 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 40), 5 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 45), 6 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 50), 7 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 55), 8 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 60), 9 }.rotated(45_deg).draw(PatternColor);
		}
	}

	// MSRenderTexture の完成には
	// 2D 描画命令の発行 (Flush) + MSAA の解決 (Resolve) が必要
	Graphics2D::Flush();
	renderTexture.resolve();

	// 完成したテクスチャを返す
	return renderTexture;
}

MultiPolygon CreateEmojiPolygons(const Emoji& emoji)
{
	return Image{ emoji }.alphaToPolygonsCentered(160, AllowHoles::No);
}

MultiPolygon MakeRoundBuffer(const MultiPolygon& polygons, int32 distance)
{
	MultiPolygon result;

	for (const auto& polygon : polygons)
	{
		result = Geometry2D::Or(result, polygon.calculateRoundBuffer(distance));
	}

	return result;
}

void Main()
{
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

	const Texture buttonTexture = CreateButtonTexture();

	const Font font{ FontMethod::MSDF, 48, Typeface::Heavy };

	const Texture emoji{ U"🗺"_emoji };

	const Rect rect{ 200, 300, buttonTexture.size() };

	const ColorF PrimaryColor{ 0.3, 0.5, 1.0 };

	const MultiPolygon polygons = MakeRoundBuffer(CreateEmojiPolygons(U"🗺"_emoji), 4).scaled(0.4);

	// .update(true) で 1.0 になるまでの時間, .update(false) で 0.0 になるまでの時間
	Transition transition{ 0.0s, 0.8s };

	while (System::Update())
	{
		const RoundRect roundRect{ rect, 10 };

		RoundRect{ rect, 10 }(buttonTexture).draw();

		const bool mouseOver = roundRect.mouseOver();

		// マウスカーソルがボタンの上に入ったときにトリガー
		transition.update((not roundRect.intersects(Cursor::PreviousPos())) && mouseOver);

		if (mouseOver)
		{
			Cursor::RequestStyle(CursorStyle::Hand);

			roundRect(buttonTexture).draw(MouseL.pressed() ? ColorF{ 0.95 } : ColorF{ 1.05 }).drawFrame(0, 2, PrimaryColor);
		}
		else
		{
			roundRect(buttonTexture).draw().drawFrame(2);
		}

		{
			const Vec2 emojiCenter = rect.getRelativePoint(0.5, 0.05);
			double angle = Math::Sin(transition.value() * 8_pi) * 6_deg * transition.value();

			{
				// emojiCenter を中心に angle だけ回転する座標変換
				const Transformer2D transformer{ Mat3x2::Rotate(angle, emojiCenter) };
				polygons.draw(emojiCenter, mouseOver ? PrimaryColor : ColorF{ 0.3, 0.25, 0.2 });
				emoji.scaled(0.4).drawAt(emojiCenter);
			}
		}

		font(U"マップ").drawAt(TextStyle::Outline(0.0, 0.2, ColorF{ 1.0 }), 26, rect.getRelativePoint(0.5, 0.7), PrimaryColor);
	}
}

2.8 完成

  • 使いやすいようクラス化します

# include <Siv3D.hpp>

// ボタンの背景テクスチャを作成する
Texture CreateButtonTexture()
{
	MSRenderTexture renderTexture{ Size{ 160, 60 }, ColorF{ 0.96 } };
	{
		const ScopedRenderTarget2D renderTarget{ renderTexture };

		const ColorF PatternColor{ 0.85 };

		for (int32 x = 0; x <= 8; ++x)
		{
			RectF{ Arg::center((x * 20), 25), 2 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 30), 3 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 35), 4 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 40), 5 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 45), 6 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 50), 7 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((x * 20), 55), 8 }.rotated(45_deg).draw(PatternColor);
			RectF{ Arg::center((10 + x * 20), 60), 9 }.rotated(45_deg).draw(PatternColor);
		}
	}

	// MSRenderTexture の完成には
	// 2D 描画命令の発行 (Flush) + MSAA の解決 (Resolve) が必要
	Graphics2D::Flush();
	renderTexture.resolve();

	// 完成したテクスチャを返す
	return renderTexture;
}

class RichButton
{
public:

	RichButton() = default;

	explicit RichButton(const Emoji& emoji)
		: m_emoji{ emoji }
		, m_bufferedEmoji{ MakeRoundBuffer(CreateEmojiPolygons(emoji), 4).scaled(EmojiScale) } {}

	void draw(const Rect& rect, const Texture& buttonTexture, const Font& font, const String& text)
	{
		const ColorF PrimaryColor{ 0.3, 0.5, 1.0 };

		const RoundRect roundRect{ rect, 10 };

		const bool mouseOver = roundRect.mouseOver();

		m_transition.update((not roundRect.intersects(Cursor::PreviousPos())) && mouseOver);

		if (mouseOver)
		{
			Cursor::RequestStyle(CursorStyle::Hand);

			roundRect(buttonTexture).draw(MouseL.pressed() ? ColorF{ 0.95 } : ColorF{ 1.05 }).drawFrame(0, 2, PrimaryColor);
		}
		else
		{
			roundRect(buttonTexture).draw().drawFrame(2);
		}

		{
			double angle = Math::Sin(m_transition.value() * 8_pi) * 6_deg * m_transition.value();
			const Vec2 emojiCenter = rect.getRelativePoint(0.5, 0.05);

			{
				const Transformer2D transformer{ Mat3x2::Rotate(angle, emojiCenter) };
				m_bufferedEmoji.draw(emojiCenter, mouseOver ? PrimaryColor : ColorF{ 0.3, 0.25, 0.2 });
				m_emoji.scaled(EmojiScale).rotated(angle).drawAt(emojiCenter);
			}
		}

		font(text).drawAt(TextStyle::Outline(0.0, 0.2, ColorF{ 1.0 }), 26, rect.getRelativePoint(0.5, 0.7), PrimaryColor);
	}

private:

	Texture m_emoji;

	MultiPolygon m_bufferedEmoji;

	Transition m_transition{ 0.0s, 0.8s };

	static constexpr double EmojiScale = 0.4;

	static MultiPolygon CreateEmojiPolygons(const Emoji& emoji)
	{
		return Image{ emoji }.alphaToPolygonsCentered(160, AllowHoles::No);
	}

	static MultiPolygon MakeRoundBuffer(const MultiPolygon& polygons, int32 distance)
	{
		MultiPolygon result;

		for (const auto& polygon : polygons)
		{
			result = Geometry2D::Or(result, polygon.calculateRoundBuffer(distance));
		}

		return result;
	}
};

void Main()
{
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

	const Texture buttonTexture = CreateButtonTexture();
	const Font font{ FontMethod::MSDF, 48, Typeface::Heavy };

	RichButton button1{ U"🗺"_emoji };
	RichButton button2{ U"🛠"_emoji };
	RichButton button3{ U"✉"_emoji };
	RichButton button4{ U"⚙"_emoji };

	while (System::Update())
	{
		button1.draw(Rect{ 40, 500, 160, 60 }, buttonTexture, font, U"マップ");
		button2.draw(Rect{ 220, 500, 160, 60 }, buttonTexture, font, U"開発");
		button3.draw(Rect{ 400, 500, 160, 60 }, buttonTexture, font, U"お知らせ");
		button4.draw(Rect{ 580, 500, 160, 60 }, buttonTexture, font, U"設定");
	}
}