LoginSignup
121
117

More than 5 years have passed since last update.

はじめよう!スプライトアニメーション

Last updated at Posted at 2015-08-19

はじめに

スプライトアニメーションとは、コマを画像一枚に敷き詰め、画像内での座標位置を連続で切り替えることで、アニメーションを実現させる手法です。

特にここ数年でどーんと色々なWebサイトで使われるようになっている気がします。私はあまり詳しくはありませんが、ゲーム制作とかでは昔から一般的な手法だったのかもしれません(RPGツクールとかでスプライト画像を見た気もします)。

そんなに難しいものでもなく、アイデア次第では美しく非常にインパクトのある表現も可能です。ここでは動作の基本をまとめてみます。試したことの無い方の参考になれば幸いです。

目次

  • アニメーションイメージ
  • スプライトアニメーションのメリット・デメリット
  • cssだけで表現してみる
  • cssとjavascriptで表現してみる
  • canvasで表現してみる

アニメーションイメージ

[ソース画像]
images.png

[アニメーション]
※途中でガクッとなるのは、画面をキャプチャしてgifアニメを作成したためです
taro.gif

画像素材は、以下利用させていただきました
http://blawat2015.no-ip.com/~mieki256/diary/201402.html
※キャラクターはかの有名な大崎一番太郎です(CV:山口勝平)

スプライトアニメーションのメリット・デメリット

メリット

パフォーマンスに優れる
全コマをまとめるためサイズは大きくなりますが、ファイルが一つで済むので、リクエスト数を劇的に減らすことができます。

色々なデータが使える
gif, jpg, png, svg...様々な拡張子が使えます。特に透過データが使えるのが一番のメリットかもしれません

動作の調整が容易
gifアニメは一旦作ってしまうと調整が大変ですが、スプライトではスピードなどアニメーションの調整は簡単です。javascriptと組み合わせて複雑な表現も可能です。

デメリット

スプライト画像を作るのが面倒くさい
画像のアニメーションを作る上では避けられない気もしますが、画像自体の調整や修正など面倒くさいです。動的にスプライト画像を生成する仕組みを入れたり、共通化を意識してデザインしたりしないと、かなりしんどいかもしれません。

画像サイズに制限がある古ーいスマホのようなものには対応できないこともあります。

cssだけで表現してみる

単純なものであればcss3のanimationのみで実現可能です。

全ソース・実際の動きは↓から確認ができます
http://nekoneko-wanwan.github.io/demo/sprite/css/

sprite.html
<div class="character"></div>
sprite.css
.character {
  margin: 100px auto 0;
  /* 画像置換 */
  background: url(../images.png) 0 0 no-repeat #ccc;
  height: 0;
  overflow: hidden;
  padding-top: 64px;
  width: 64px;
  /* アニメーション */
  animation: sprite1 0.5s steps(7, start) infinite;
}

@keyframes sprite1 {
  0%   {background-position: 0 0;}
  100% {background-position: -448px 0;}
}
  • 要素に対して画像置換を行ない、背景にスプライト画像を指定します
  • 一コマ64×64の画像が横に8個並んだ画像を使用しています
  • animationのtiming-functionにsteps()を設定し、等間隔に出力されるようにします

steps()について

steps(number_of_steps, direction)
number_of_steps
 厳密に正の <整数値> で、ステップ関数を構成する等間隔の段数を示すものです。
direction
 関数が 左連続か右連続 かを表すキーワードです:
 - start は左連続関数を表し、従ってアニメーションの開始時に最初のステップが発生します。
 - end は右連続関数を表し、従ってアニメーションの完了時に最後のステップが発生します。

引用: https://developer.mozilla.org/ja/docs/Web/CSS/timing-function

ここでは 0から-448pxまでの間を7回 等間隔ごとにbackground-positionをずらすようにしています。結果的に64px単位でコマが切り替わっていくようになります。
つまりズラす回数をstepsに、ズラす回数×コマ幅(縦にズラす場合は高さ)の値をkeyframesの100%に指定すれば、期待通りの動作になるかと思います。

cssとjavascriptで表現してみる

javascriptと組み合わせることで、cssのanimation非対応ブラウザに対応・複雑な表現を行うことができます。この場合、大きく分けて2つのパターンが考えられます。

  1. jsで直接スタイルを修正していきpositionをズラしていく
  2. jsはあくまでclassの付け替えのみを行ない、スタイルは全てcss側で制御する

前者は数値の計算が不要で調整もしやすいですが、直接スタイルを変更するため重たくなりがちです。
後者はパフォーマンスは良く、jsとスタイルを分離できますが、いかんせん面倒くさいです(cssプリプロセッサやcalc()を使えば、大分手間は軽減するかとは思いますが)。

※1.2でどのくらいパフォーマンス差がでるかは未検証です(良い調べ方が思いつきませんでした......)

全ソース・実際の動きは↓から確認ができます
http://nekoneko-wanwan.github.io/demo/sprite/css-js/

直接スタイル変更.js
function changePosition() {
  var $target = $('.character');
  var ROW     = 64;
  var LIMIT   = 7;
  var i       = 0;

  setInterval(function(){
    // 'px ' ←半角スペース必須
    var move = -(ROW * i) + 'px ' + 0 +'px';
    $target.css({
      "background-position": move
    });
    if (i === LIMIT) {
      i = 0;
    } else {
      i++;
    }
  }, 70);
}
changePosition();
classの付け替え.js
function changeClass() {
  var $target = $('.character');
  var LIMIT   = 7;
  var i       = 0;

  setInterval(function(){
    $target.attr('class', 'is-position-' + i).addClass('character');
    if (i === LIMIT) {
      i = 0;
    } else {
      i++;
    }
  }, 70);
}
classの付け替え.css
.is-position-0 { background-position: 0 0;}
.is-position-1 { background-position: -64px 0;}
.is-position-2 { background-position: -128px 0;}
.is-position-3 { background-position: -192px 0;}
.is-position-4 { background-position: -256px 0;}
.is-position-5 { background-position: -320px 0;}
.is-position-6 { background-position: -384px 0;}
.is-position-7 { background-position: -448px 0;}

canvasで表現してみる

canvas内で使用することで、パフォーマンスを保ちつつ複雑な表現が可能となります(DOM操作を行う必要が無い)。ここでは大崎一番太郎が私のHPを削っていくようなアニメーションを作成してみました。

[アニメーションイメージ]
taro_move.gif

全ソース・実際の動きは↓から確認ができます
http://nekoneko-wanwan.github.io/demo/sprite/canvas/

canvas.html
<canvas id="character" style="display: block; background-color: #7FDBFF;"></canvas>
canvas.js
function character() {
    var canvas    = document.getElementById('character');
    var context   = canvas.getContext('2d');
    var img       = new Image();
    var row       = 64;  // 一コマの横幅
    var col       = 64;  // 一コマの縦幅
    var step      = 0;   // コマ切り替えの段階
    var limit     = 7;   // コマ切り替えの上限
    var move      = 0;   // 横にスライドさせる位置
    var ax        = 3;   // 横の移動量
    canvas.width  = 500;
    canvas.height = 80;

    img.src = '../images.png?' + new Date().getTime();

    function render() {
      /* 矩形とテキストの描画 */
      context.clearRect(0, 0, 500, 100);
      context.fillStyle = "rgb(200, 0, 0)";
      context.fillRect(move + row - 5, 20, 500 - move + row, 40);
      context.fillStyle = "rgb(175, 0, 0)";
      context.fillRect(move + row - 5, 55, 500 - move + row, 5);
      context.fillStyle = "rgb(255, 255, 255)";
      context.font = '16px/2 sans-serif';
      context.fillText('MY HP', move + row + 5, 45);

      /* キャラクター画像の描画 */
      context.drawImage(img, row * step, 0, row, col, move, 0, row, col);
      if (step < limit) {
        step++;
      } else {
        step = 0;
      }
      if (move < 500 - row) {
        move = move + ax;
      } else {
        move = 0;
      }
      setTimeout(render, 50);
    }

    img.onload = function() {
      render();
    };
}

character();

大崎一番太郎がうごいた\(^0^)/

121
117
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
121
117