作品紹介 | 音階が見えるビジュアライザー

Siv3D Advent Calendar 2013, 14 日目の記事です。

今日は @hamukun8686 さんが Siv3D で制作した「音階が見えるビジュアライザー」を紹介します。

ソースコードが Qiita | 音階が見えるビジュアライザー に掲載されているので、Siv3D をインストールしていればすぐに手元で実行できます。

プログラムは Qiita | Siv3D で音楽プレイヤーを作る を拡張したもので、スペクトラムをうまく円状に配置して音階を表現しているほか、マイク入力にも対応しています。

これからも Qiita には新しいサンプルプログラムを掲載していくので、クリエイターのみなさんもどし!どし!オリジナル、もしくは拡張のプログラムを投稿して情報交換していきましょう。2014 年中に Siv3D タグの記事 が 50 個できればいいなーと思っています。

ゲームとメディアアートのための C++ ライブラリ「Siv3D」のこれまでとこれから

C++ Advent Calendar 2013 および Siv3D Advent Calendar 2013, 13 日目の記事です。

「Siv3D」C++ で楽しく簡単にゲームやメディアアートを作ることを目的としたライブラリです。2008 年から開発を始め、2012 年に α 版を公開、今年 9 月には IPA 未踏事業に採択 され、開発を加速しています。

設計方針

C++ の先進的な機能を取り入れ、コードの読みやすさ・書きやすさと、パフォーマンス、機能性を重視しています。
最新版の Siv3D December 2013 は 10 月にリリースされたばかりの Visual Studio 2013 に対応し、ライブラリからチュートリアル、リファレンスのすべてが現代的な C++ で書かれています。(最新の C++ の機能について知りたい方は こちら

サンプル [1/6]

# include <Siv3D.hpp>

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

	while (System::Update())
	{
		Circle(Mouse::Pos(), 100).draw();

		font.draw(Format(Mouse::Pos()), 50, 200, Palette::Orange);
	}
}

サンプル [2/6]

# include <Siv3D.hpp>

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

	while (System::Update())
	{
		// 位置 (100,50) にテクスチャを描く
		texture.draw(100, 50);
	}
}

サンプル [3/6]

# include <Siv3D.hpp>

void Main()
{
	Image image{ 640, 480, Palette::White };

	DynamicTexture texture{ image };

	while (System::Update())
	{
		if (Input::MouseL.pressed)
		{
			const Point pos = Input::MouseL.clicked ?
				Mouse::Pos() : Mouse::PreviousPos();

			Line(pos, Mouse::Pos()).write(image, 8, Palette::Blue);

			texture.fill(image);
		}

		texture.draw();
	}
}

サンプル [4/6]


Point, Rect, Circle, Line, Triangle, Quad, Polygon 等さまざまな図形同士であたり判定ができます。

# include <Siv3D.hpp>

void Main()
{
	const Rect rect(20, 20, 200, 100);

	const Circle circle(150, 300, 100);

	const Polygon star
	{
		{ 430, 100 }, { 470, 240 },
		{ 610, 240 }, { 505, 325 },
		{ 545, 460 }, { 430, 380 },
		{ 315, 460 }, { 355, 325 },
		{ 250, 240 }, { 390, 240 }
	};

	while (System::Update())
	{
		const Circle player(Mouse::Pos(), 30);

		const bool r = player.intersects(rect);

		const bool c = player.intersects(circle);

		const bool s = player.intersects(star);

		rect.draw(r ? Palette::Red : Palette::Yellow);

		circle.draw(c ? Palette::Red : Palette::Yellow);

		star.draw(s ? Palette::Red : Palette::Yellow);

		player.draw();
	}
}

サンプル [5/6]

# include <Siv3D.hpp>

void Main()
{
	if (!Kinect::IsConnected())
	{
		return; // Kinect の接続チェック
	}

	if (!Kinect::Start())
	{
		return; // Kinect の起動
	}

	DynamicTexture texture;

	optional<Skelton> skelton;

	while (System::Update())
	{
		if (Kinect::HasNewDepth())
		{
			Kinect::GetDepthTexture(texture);
		}

		if (const auto s = Kinect::GetSkelton())
		{
			skelton = s.get();
		}

		texture.draw();

		if (skelton)
		{
			for (const Vec2& p : skelton.get().screenPositions)
			{
				Circle(p, 10).draw();
			}
		}
	}
}

サンプル [6/6]


83 行の C++ プログラムで音楽プレイヤーを作ることができます。
コードは Qiita | Siv3D で音楽プレイヤーを作る で紹介しています。

ダウンロードして 3 秒で始められる

Visual Studio 2013 をインストールしていれば、Siv3D のインストーラを実行するだけで、すぐに開発を始めることができます。
Visual Studio の「新しいプロジェクト」メニューに項目が追加される

使い方を学ぶ

入門サイト 「Play Siv3D!」 では Siv3D のチュートリアル、リファレンスなどのコードサンプルを 200 以上用意しています。
まだ準備中の部分もありますが、2014 年春までには一通りのドキュメントを完成させる予定です。

ゲーム開発で使われる Siv3D


Siv3D を使って制作したゲームが サークル WCE で公開 されています。
今年の冬コミでも 7 つの新作ゲームが販売される予定です。
そのほかデジゲー博や、ニコニコ動画 でも Siv3D を利用した作品が登場しています。

今後のアップデート

今月末のアップデートでは以下の機能を追加する予定です。
・3D 描画を正式機能に格上げ、サンプルを追加

・手書き文字認識

・GIF 画像保存時にディザリングの有無の指定
GUIラジオボタンを追加

2014 年には
・3D グラフィックスの強化

物理エンジンとの連動
スクリプト対応
マルチプラットフォーム対応(Mac OS X, Android
などのアップデートを予定しています。

Siv3D のこれから

国内では HSP や DX ライブラリの後継になり、海外の C++ プログラマやプログラミング入門者にも使ってもらえるライブラリを目指しています。
Siv3D を使って初めてプログラミングをする世界中の子どもたちに「プログラミングってこんなに面白いんだ!」「C++ ってすげー!」と思ってもらうのが夢です。

Siv3D のダウンロード

ダウンロードからサンプル実行までの手順を Play Siv3D! | Siv3D を使う準備 で紹介しています。Enjoy Siv3D!


明日の C++ Advent Calendar は @USAGI_WRP さんです。よろしくお願いします!
Siv3D Advent Calendar は引き続き 14 日連続で僕がお送りします。

GUI のテーマカラーと背景を変更する

Siv3D Advent Calendar 2013, 12 日目の記事です。
今日は GUI のビジュアルを変更する機能を紹介します。

GUI の見た目は GUISkin で設定します。
GUISkin は設定項目が多いので、通常は GUISkin::Default(Color) 関数を使って初期化します。このときの Color がテーマカラーになります。


デフォルトは青色です。

# include <Siv3D.hpp>

void Main()
{
	GUI gui(GUISkin::Default());

	gui.addButton(L"PlayButton", { L"Play" });

	gui.addButton(L"PauseButton", { L"Pause" });

	gui.addButton(L"OpenButton", { L"Open" });

	gui.addNewLine();

	gui.addSlider(L"Slider", { 0.0, 1.0, 0.3, 500 });

	gui.addNewLine();

	gui.addSpace({ 50, 200 });

	while (System::Update())
	{
	
	}
}


チョコレート色に

	GUI gui(GUISkin::Default({ 120, 40, 10 }));


緑色に

	GUI gui(GUISkin::Default({ 40, 140, 50 }));

GUISkin の backgroundTexture プロパティに Texture を、repeatBackgroundTexture プロパティに繰り返しマッピングの有無を指定して、おしゃれな背景の GUI を作ることができます。

# include <Siv3D.hpp>

void Main()
{
	GUISkin skin = GUISkin::Default(Dialog::GetColor({ 0, 140, 220 }));

	skin.backgroundTexture = Dialog::OpenTexture();

	skin.repeatBackgroundTexture = true;

	GUI gui(skin);

	gui.addButton(L"PlayButton", { L"Play" });

	gui.addButton(L"PauseButton", { L"Pause" });

	gui.addButton(L"OpenButton", { L"Open" });

	gui.addNewLine();

	gui.addSlider(L"Slider", { 0.0, 1.0, 0.3, 500 });

	gui.addNewLine();

	gui.addSpace({ 50, 150 });

	while (System::Update())
	{
	
	}
}

森をイメージした GUI デザインのサンプル。

宇宙をイメージした GUI デザインのサンプル。

GUI のカスタマイズ可能な項目は今後も増やしていく予定です。
自分のゲームだけの GUI をデザインしてみるのも面白そうですね。

イベントタイマー

Siv3D Advent Calendar 2013, 11 日目の記事です。
今日は December 2013 で追加されたイベントタイマー機能を紹介します。

EventTimer は Timer の強化版で、設定したイベント時間の通過を教えてくれます。

イベントの設定は EventTimer::set(event, time)
あるイベントを通過したかどうかは EventTimer::onTriggered(event) で判定します。

EventTimer::clearEvents() するまでイベント情報は消えないので、EventTimer::restart() で何回でもイベントを発生させることができます。
Timer と違い、イベント通過判定のために毎フレーム EventTimer::update() する必要がある点だけ注意してください。

サンプル


# include <Siv3D.hpp>

void Main()
{
	Graphics::SetBackground(Palette::Gray);

	EventTimerMillisec eventTimer;
	eventTimer.setEvent(L"Red", 2000);
	eventTimer.setEvent(L"Blue", 6000);
	eventTimer.setEvent(L"Green", 4000);

	eventTimer.start();

	while (System::Update())
	{
		const unsigned elapsed = eventTimer.update();

		if (eventTimer.onTriggered(L"Red"))
		{
			Println(L"Red: ", elapsed);

			Graphics::SetBackground(Palette::Red);
		}
		else if (eventTimer.onTriggered(L"Green"))
		{
			Println(L"Green: ", elapsed);

			Graphics::SetBackground(Palette::Green);
		}
		else if (eventTimer.onTriggered(L"Blue"))
		{
			Println(L"Blue: ", elapsed);

			Graphics::SetBackground(Palette::Blue);
		}

		if (Input::MouseR.clicked)
		{
			Println(L"restart");

			Graphics::SetBackground(Palette::Gray);

			eventTimer.restart();
		}
	}
}

色のいろんな作り方

Siv3D Advent Calendar 2013, 10 日目の記事です。
今日は Siv3D での色の作り方を紹介します。

Color 型のコンストラク

Color(Palette)

140 種類の Web カラーネーム が定義されています。

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Circle(100, 100, 100).draw(Palette::Orange);
	}
}
Color(r, g, b)
# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Circle(100, 100, 100).draw({ 80, 240, 120 });
	}
}
Color(r, g, b, a)
# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Rect(100, 100).draw();

		Circle(100, 100, 100).draw({ 80, 240, 120, 80 });
	}
}
Color(Palette, a)
# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Rect(100, 100).draw();

		Circle(100, 100, 100).draw({ Palette::Red, 80 });
	}
}
Color(rgb)
# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Circle(100, 100, 100).draw(Color(120));

		Circle(100, 300, 100).draw(Color(220));
	}
}
Color(rgb, a)
# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Rect(100, 100).draw();

		Circle(100, 100, 100).draw({ 0, 180 });
	}
}
Color(String)

3 桁もしくは 6 桁の 16 進数カラーコードで色を表現します。

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Circle(100, 100, 100).draw(Color(L"#F00"));

		Circle(100, 300, 100).draw(Color(L"#2580D0"));
	}
}

そのほかの便利な機能として
[0.0, 1.0] で各成分を表す ColorF 型

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Circle(100, 100, 100).draw(ColorF(0.1, 0.6, 0.9));

		Circle(100, 200, 100).draw(ColorF(0.8));

		Circle(100, 300, 100).draw(ColorF(0.5, 0.4));
	}
}

HSV 表色系で色を表現する HSV

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Circle(100, 100, 100).draw(HSV(60));

		Circle(100, 200, 100).draw(HSV(120, 0.5, 1.0));

		Circle(100, 300, 100).draw(HSV(240, 1.0, 0.8));
	}
}

Color(255,255,255,alpha) を返す Alpha(alpha) 関数

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Circle(100, 100, 100).draw(HSV(0));

		Circle(100, 200, 100).draw(Alpha(120));
	}
}

HSV 型の演算

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		Circle(100, 100, 100).draw(Color(0, 64, 160));

		Circle(100, 200, 100).draw(Color(0, 64, 160) + HSV(80, 0, 0));

		Circle(100, 300, 100).draw(Color(0, 64, 160) + HSV(0, 0.5, 0));

		Circle(100, 400, 100).draw(Color(0, 64, 160) + HSV(0, 0, 0.5));
	}
}

といった機能があります。
必要な色を最小限の書き方で得られるようになると便利です。

HSV 表色系のサンプル


マウスを動かすと色相が変化します。

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		for (int y = 0; y <= 10; ++y)
		{
			for (int x = 0; x <= 10; ++x)
			{
				const Color color = HSV(Mouse::Pos().x, x / 10.0, 1.0 - y / 10.0);

				Rect(20 + 40 * x, 20 + 40 * y, 40, 40).draw(color);
			}
		}
	}
}

ペンタブレットを使う

Siv3D Advent Calendar 2013, 9 日目の記事です。
今日はペンタブレット入力の機能を紹介します。

※この記事は Siv3D December 2013 に基づいています。最新の Siv3D のコードは
リファレンス | ペンタブレット で入手できます。

主要な関数は 3 つです。
地面に対するペンの傾きを取得する Pentablet::DegreeXZ()
垂直な軸まわりのペンの回転角度を取得する Pentablet::DegreeY()
筆圧を取得する Pentablet::Pressure()

座標やクリックは Mouse::Pos() や Input::MouseL / MouseR に反映されます。

# include <Siv3D.hpp>

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

	if (!Pentablet::SupportsPressure())
	{
		return; // 筆圧測定に対応していない
	}

	while (System::Update())
	{
		// 地面に対する傾き [0, 90]
		const int degreeXZ = Pentablet::DegreeXZ();

		// 垂直な軸まわりの回転角度 [0, 359)
		const int degreeY = Pentablet::DegreeY();

		// 筆圧 [0.0, 1.0]
		const double pressure = Pentablet::Pressure();

		Circle(Mouse::Pos(), pressure * 200).draw(Palette::Skyblue);

		Circle(Mouse::Pos() + Circular(pressure * 200, Radians(degreeY)), 20).draw(Palette::Red);

		font.draw(Format(
			L"XZ: ", degreeXZ, L'\n',
			L"Y:", degreeY, L'\n',
			L"pressure: ",pressure));
	}
}
サンプルゲーム

筆圧に応じて水色のリングの大きさが変わります。
リングとリングの間に収まるちょうどいい状態を維持するとクリアです。

# include <Siv3D.hpp>

Circle CreateCircle()
{
	return{ Random(80.0, 560.0), 
			Random(80.0, 400.0), 
			Random(10.0, 80.0) };
}

void Main()
{
	const Sound sound(L"Example/Sound.mp3");

	const Font font(30);

	if (!Pentablet::SupportsPressure())
	{
		return;
	}

	Circle circle = CreateCircle();

	const int maxCount = 15;

	int count = 0;

	while (System::Update())
	{
		const Circle outerCircle = circle.stretched(20.0);

		const double pressure = Pentablet::Pressure()*100.0;

		const Circle pressureCircle(Mouse::Pos(), pressure);

		if (circle.r <= pressure && pressure <= outerCircle.r
			&& circle.within(pressureCircle)
			&& pressureCircle.within(outerCircle))
		{
			++count;
		}
		else
		{
			count = 0;
		}

		if (count == maxCount)
		{
			count = 0;

			sound.playMulti();

			circle = CreateCircle();
		}

		circle.drawFrame(1.0, 1.0);
		
		outerCircle.drawFrame(1.0, 1.0);
		
		pressureCircle.drawFrame(1.0, 1.0, Palette::Skyblue);

		pressureCircle.drawPie(0.0, TwoPi / maxCount*count, Palette::Skyblue);
	}
}