あさちゅんのゲームブログ

UnityやSiv3Dに関するゲーム開発メモを残していきます

Siv3Dで簡単なアニメーションを作る

ゲームといえば可愛く、かっこよく動いてなんぼですよね。
という訳で今回は超簡単にアニメーションを作ろうと思います。

できあがると下のキャラクターみたいに動くようになります!
この方法だと簡単な代わりに容量とイラストレーターさんの気合が必要になりますが、、、


ちなみにこのゲームはWCEの公式サイトからダウンロードできます。

今回はサンプルを作ったので、もし自作するのが面倒という方はGitHubからダウンロードしていただけるとありがたいです。

github.com

用意する画像

まず、下のような1コマ1コマを横に繋げた画像を用意します。
この1コマを時間ごとにずらして描画する感じです。


なぜ、1コマごとに画像を区切らないかというとファイルを開くコストの都合とモーションごとにまとめた方が管理が楽だからです。

それではこの画像を扱うAnimeクラスを作ってみましょう。

Animeクラス

コンストラクタでテクスチャとそれに含まれるコマ数を受け取り、draw関数で描画するクラスを作ります。

# include <Siv3D.hpp>

class Anime
{
public:
	Anime(const Texture& texture, int size) :
		m_texture(texture),
		m_size(size),
		m_index(0) {}

	void draw()
	{
		m_texture.uv(static_cast<double>(m_index) / m_size, 0.0, 1.0 / m_size, 1.0).draw();

		++m_index;

		if (m_index >= m_size)
		{
			m_index = 0;
		}
	}

private:
	Texture m_texture;
	int m_size;
	int m_index;
};

void Main()
{
	// 画像は自分の環境にあったものを使用してください。
	Texture texture(L"AsachunAnime.png");

	Anime anime(texture, 4);

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

m_textureは扱うテクスチャ、m_sizeはそれに含まれるコマの数、m_indexは現在どのコマを描画しているかを保存する変数です。

draw関数を見てみましょう。
Texture::uv関数を使用しています。

このuv関数はテクスチャの左上を(0, 0)、右下を(1, 1)とした座標でテクスチャを切り抜ける関数です。

今回の場合切り抜きたいテクスチャの横幅は1.0 / (コマ数)になります。
なので、左上の座標はそれにm_indexをかけたm_index / (コマ数)になります。m_indexは描画する度に変わるので、これでパラパラ漫画のようにアニメーションができる訳です。

この時、片方をdoubleにキャストしておかないと整数の割り算になって目的の動作をしなくなるので気をつけてください。横幅の時、1じゃなく1.0と書いたのもこのためです。

縦はもちろん0.0から1.0の間を切り取ります。

Animeクラス 改良版

さきほどのを実行すればわかりますが、一回描画するごとに絵が変わるので速すぎて見えませんでした。
また、今のままだと座標が指定できませんし、draw関数がm_indexを進めるのと描画する複数の作業をしているので関数を分けましょう。

# include <Siv3D.hpp>

class Anime
{
public:
	Anime(const Texture& texture, int size, int frame) :
		m_texture(texture),
		m_size(size),
		m_frame(frame),
		m_index(0),
		m_count(0) {}

	void update()
	{
		++m_count;

		if (m_count > m_frame)
		{
			m_count = 0;
			++m_index;

			if (m_index >= m_size)
			{
				m_index = 0;
			}
		}
	}

	void draw(const Vec2& pos) const
	{
		m_texture.uv(static_cast<double>(m_index) / m_size, 0.0, 1.0 / m_size, 1.0).draw(pos);
	}

private:
	Texture m_texture;
	int m_size;
	int m_frame;
	int m_index;
	int m_count;
};

void Main()
{
	Texture texture(L"AsachunAnime.png");

	Anime anime(texture, 4, 10);

	while (System::Update())
	{
		anime.update();
		anime.draw(Mouse::Pos());
	}
}

新たにm_frameとm_countを用意して何回かupdate関数か呼ばれるとm_indexが変わるようにしました。

またdraw関数をupdate関数とdraw関数に分けて、draw関数はconstメンバ関数にしました。
これでHamFrameworkなどで使いやすくなりました。


素材を用意するのはちょっと大変かもしれませんが、難しい処理なくアニメーションを作ることができました。
素材さえあればどんな複雑なものも動かせます、素材さえあれば、、、

また、上に貼った通りこれを改良したサンプルをGitHubに用意したので覗いていただけると幸いです。

おまけ

失敗したかもという人用に完成版を用意しました。

gist.github.com
使用したソフト
Microsoft Visual Studio Express 2013 for Windows Desktop
Siv3D(January 2015 v3)