サイトのトップへ戻る

libGDX ドキュメント 日本語訳

サイト内検索

2D アニメーション

2D アニメーションは、静止画を使って動くイラストを作成する技術です。この記事ではlibGdxでアニメーションを作成する方法を説明します。

EDIT: この Animation クラスを使用します。



詳細

アニメーションは、設定された間隔で順番に表示される複数のフレームで構成されます。 走っている男の画像を取得してその画像を無限にループ再生させることで、走る男のアニメーションが出来上がります。

以下の画像は男が走っている全サイクルを表します。 これはスプライトシートと呼ばれます。各枠がスプライトにあたり、これはフレームと呼ばれます。 走るアニメーションを作成するには、時間経過ごとに次々とスプライトを描写する必要があります。

キャラクターが走る速さに応じて、画面上にフレームが表示される時間を変える必要があります。 フレームレートとは、1秒間にフレームを切り替える回数のことです。 スプライトシートを見ると、走る男のサイクルは全部で30フレーム(6列 x 5行)あることが分かります このキャラクターのサイクルを1秒間で一巡させるには、1秒で30フレームを全て表示する必要があります。 この場合、フレームレートは30 FPS (Frames Per Second)になります。名前の通りです。 さらに進んで、状態時間(フレーム時間)を計算するのは簡単にできます。状態時間とは、次のフレームに切り替わるまでにそのフレームをどれだけの時間を表示するかを表します。 これは 1 秒/ 30 = 0.033秒となります。

言い換えると、30FPSでアニメーションをする場合は現在のフレームを 0.033 秒ごとに切り替える必要があります。

アニメーションは非常にシンプルな状態マシンです。走る男はスプライトシートごとに30の状態を持っています。 フレーム番号は走る男の切り替える順番を表します。

状態マシンでは、同時に二つの状態を持つことはできません。状態の操作を行うのはとても簡単です。 キャラクターの状態が1の場合、それに関連付けられた番号のspriteが描写されます。 その状態を0.033秒間保ち、時間が経過すると次の状態である2へ切り替わります(遷移)。 最後の状態/フレーム (30)になるまでこの処理が繰り返されます。

アニメーションのループ処理では、アニメーションが最後のフレームに達した際に最初のフレームに戻って改めてアニメーションを行います。

libGdxでアニメーションを使用するのはとても簡単です。 スプライトシートのサイズについてはある制限があるので覚えておいてください: OpenGL 1.xを使用する場合、スプライトシートのサイズは2のべき乗にする必要があります (詳細情報については Texture を確認してください)。

以下のコードではスプライトシート animation_sheet.pngを使ってAnimation (コード) を作成し、画面にアニメーションを描写します。 とても基本的な ApplicationListenerを実装しています。 これの作成方法とこれがどういったものかを知りたい場合は、このページの textureの項目を参照してください。

public class Animator implements ApplicationListener {

    private static final int        FRAME_COLS = 6;         // #1
    private static final int        FRAME_ROWS = 5;         // #2

    Animation                       walkAnimation;          // #3
    Texture                         walkSheet;              // #4
    TextureRegion[]                 walkFrames;             // #5
    SpriteBatch                     spriteBatch;            // #6
    TextureRegion                   currentFrame;           // #7

    float stateTime;                                        // #8

    @Override
    public void create() {
        walkSheet = new Texture(Gdx.files.internal("animation_sheet.png")); // #9
        TextureRegion[][] tmp = TextureRegion.split(walkSheet, walkSheet.getWidth()/FRAME_COLS, walkSheet.getHeight()/FRAME_ROWS);              // #10
        walkFrames = new TextureRegion[FRAME_COLS * FRAME_ROWS];
        int index = 0;
        for (int i = 0; i < FRAME_ROWS; i++) {
            for (int j = 0; j < FRAME_COLS; j++) {
                walkFrames[index++] = tmp[i][j];
            }
        }
        walkAnimation = new Animation(0.025f, walkFrames);      // #11
        spriteBatch = new SpriteBatch();                // #12
        stateTime = 0f;                         // #13
    }

    @Override
    public void render() {
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);                        // #14
        stateTime += Gdx.graphics.getDeltaTime();           // #15
        currentFrame = walkAnimation.getKeyFrame(stateTime, true);  // #16
        spriteBatch.begin();
        spriteBatch.draw(currentFrame, 50, 50);             // #17
        spriteBatch.end();
    }
}


設定

#1#2 ではシートの横方向と縦方向にどれだけのspriteが配置されているかを表す定数を定義しています。

: スプライトシートでは同じサイズのフレームが全て整列して保持されています。

#3 - libGdxのアニメーション実装であるwalkAnimantion オブジェクトの宣言。

#4 - シート全体を一つの画像(テクスチャ)として保持するTexture 。

#5 - TextureRegion オブジェクトの配列としてwalkFrames を宣言します。この配列ではアニメーションの各フレーム(sprite)を保持します。配列の最初の要素で右上のフレームが格納され、二つ目の要素にはそれの右隣のフレームが格納される、といった具合になります。その行の最後の要素に達すると、次の行の一番左の要素へ移って同じ処理を続けます。

#6 - SpriteBatch は画面上に texture を描写するのに使用されます。

#7 - この変数はカレントフレームを保持しており、描写命令を実行した場合にはこのTextureRegionが描写されます。

#8 - stateTime はアニメーションを開始してから経過した秒数です。これを使用してアニメーションのフレーム状態を決定します。これはシンプルな蓄積用の変数で、これに基づいてアニメーションは次のフレーム状態へ切り替わるタイミングを知ることができます。

例えば、アニメーションが 30FPS の場合、33.3ミリ秒経過する度にフレーム状態を変更します。 update イベントが10ミリ秒ごとに発生する場合は、stateTimeで経過時間を蓄積保存して updateイベントが4回発生する度にアニメーションは次のフレーム状態へ切り替わります。

#9 - プロジェクトの assetsディレクトリに置かれているanimation_sheet.pngからテクスチャを作成します。 (プロジェクトを設定する方法を確認してください)

#10 - #11 - テクスチャで便利な split メソッドを使用して、テクスチャからフレームの二次元配列を取得します。この処理はフレームが全ての同じサイズの場合しか行えないので注意してください。それから、一時変数tmpを使用して walkFrames 配列に値を格納します。アニメーションは一次配列でないと動作しないので、二次配列から一時配列に変換する処理が必要なのです。

例えば各フレームを別々のファイルから読み込むなど、 walkFrames にはあなたの合ったやり方で値を格納できます。 ただ、例に挙げた方法だとパフォーマンスに問題があるのでお勧めはしません。

#11 - ここで Animation が作成されます。一つ目の引数では、各フレームに割り当てられる時間をAnimationに指示します。これは秒単位の値で設定します。 アニメーションのフレームを増やして割り当て時間を短くすれば、 動きがより滑らかになります。 ですが、これはメモリ消費が多くなります。 二つ目に引数は、全てのフレームが格納された配列です。配列の最初の要素がアニメーションの最初のフレーム、といった具合です。

#12 - フレームを描写する SpriteBatch を初期化します。

#13 - stateTime を 0にリセットします。各render呼び出しの時間の累積を開始します。



render メソッド

#14 - 各フレームで画面をクリアします。

#15 - 最後に描写が行われてからの経過時間を stateTimeに加算します。

#16 - カレントフレームを取得します。これは Animation に現在の時間を渡すことで取得できます。 二つ目の引数はループ処理をするかどうかを表します。 trueを設定すると、最後のフレームを表示した後にアニメーションを再スタートするよう指示したことになります。

#17 - とても素晴らしいSpriteBatch を使って、画面の(50,50)位置にカレントフレームを描写します。

上記コードを実行すると、走る男のとてもスムーズなアニメーションが表示されます。

以下のコンストラクタを使うと、アニメーションの作成がとても簡単になります。

メソッドのシグネチャ 説明
Animation (float frameDuration, TextureRegion... keyFrames) 一つ目に引数はフレーム時間で、二つ目の引数はアニメーションを作成するTextureRegion(フレーム)の配列です


ベストプラクティス

  • フレームを一つのテクスチャにまとめて、描写を最適化する
  • ゲームの種類に応じて妥当な数のフレームを使う。リアルな動きを見せるにはそれだけ多くのフレームが必要ですが、レトロなアーケードゲームの場合は4フレームで十分です。


ゲーム素材

スプライトシートは ここから取得してください。