AscAnimeの実装の紹介
自分がGitHubに上げているAscAnimeの作った時に苦労したこととか、こんな方法を使っているとかを紹介しようと思います。
もしかしたら、その中に他のことでも使えるものもあるかもしれませんし、何より自分でこれどうやって作ったんだっけ?ってならないように、、、
github.com使い方
まず、asc::Animeクラスは以下のように使います。
# include <Siv3D.hpp> # include "AscAnime.hpp" void Main() { Texture texture(L"AsachunAnime.png"); asc::Anime anime(texture, 4, {5, 15, 5, 15}); while (System::Update()) { anime.update(); anime.resize(200, 200).rotate(Radians(10)).draw(Mouse::Pos()); } }
フレームの描画回数を各フレームごとに個別に指定することができ、今は使っていませんが描画回数を0に指定したフレームは描画されません。
またTextureと同様にresizeやrotateに対応しています。
それではこれを作るときに苦労したことや、これ他でも使えるんじゃないかってところを紹介しています。
コンストラクタのオーバーロード
Anime::Anime() {} Anime::Anime(const Texture& texture, unsigned size, unsigned count) : m_texture(texture), m_size(size), m_frame(size, count), m_index(0), m_count(0) {} Anime::Anime(const Texture& texture, unsigned size, const Array<unsigned>& frame) : m_texture(texture), m_size(size), m_frame(frame), m_index(0), m_count(0) {}
所々に現れているArrayはstd::vectorのSiv3D版だと思ってください。機能は同じなので説明は割愛します。
1番上の何もしないコンストラクタはstd::vectorなどのコンテナに突っ込む時に必要なのでとりあえず書いときましょう。
2個目のコンストラクタではArrayの初期化にunsignedを2つを指定しています。これはサイズが1つ目の引数で、各要素が2つ目の引数の値を持つという初期化方法でシンプルにかけるのでオススメです。
最後のコンストラクタは引数にArrayそのものを指定しています。このように書いておくと前項のコードのように{5, 15, 5, 15}のように初期化することができます。これは初期化リストといって他のSTLでも使えるので覚えていて損はないと思います。
デバッグ用機能
asc::AnimeのsetFrame関数を見てみましょう。
void Anime::setFrame(const Array<unsigned>& frame) { #ifdef _DEBUG if (frame.size() != m_size) { LOG(L"asc::Anime frameの枚数がsizeと一致しません。"); } #endif m_frame = frame; }
ここでプリプロセッサを使用しています。
Visual Studioの機能でデバッグビルド時には"_DEBUG"マクロを定義してくれています。それを利用してデバッグ時にはほしいけど、リリース版には含めたくない機能を#ifdef...#endifで囲んで実現しています。
小さい規模ならいいですが、開発が進んでくると開発用機能はどんどん必要になってくるのでこのようなこともゲームを作る上では大切な気がします。
またLOGはSiv3Dの機能でSiv3D製ソフトを起動した時にできるログファイルに文章を書き込めます。デバッグ時には非常に役立つ機能です。
resizeやrotateを自前クラスに実装する
asc::Animeのget関数を見てみましょう。
const TextureRegion Anime::get() const { return m_texture.uv(static_cast<double>(m_index) / m_size, 0.0, 1.0 / m_size, 1.0); }
関数の返り値がTextureではなく、TextureRegionになっています。実は同じテクスチャでも一度uv関数やoperator()を通すとTextureRegionという型に変わります。
uv関数やoperator()を同じテクスチャに2回使えないのはこのためです。
このTextureRegionにもTextureと同じくresizeやrotateが実装されているので、このTextureRegionを返すだけでSiv3Dの便利な関数が使えるようになります。
また余談ですがTextureやTextureRegionはrotate関数などを使って回転させるとTexturedQuad型に変化します。
resize().rotate()は大丈夫でもrotate().resize()がダメなのはこのためです。使う順番には気を付けましょう。
使い方のコードでget関数が出ていないのは、resizeなどのSiv3Dの関数と見た目を同じにした関数を実装してその内部でこの関数を使っているためです。
ただ、ここのところはもう少しやりようがあった気がします、、、