Spriteの元画像をテクスチャアトラスっぽく使ってみる

この記事は、[phina.js Advent Calendar 2016](http://qiita.com/advent-calendar/2016/phinajs) 12/3の記事です。
昨日 → [phina.jsでbulletml.jsを使う！](http://github.dev7.jp/b/2016/12/03/phinajsadvcal20161202/) by [daishi_hmr](http://qiita.com/daishi_hmr)さん
明日 → [phina+websocketの作る例](http://qiita.com/tamochu3141/items/8094aec3348dc9a6ae9d) by [tamochu3141](http://qiita.com/tamochu3141)さん
#はじめに
**phina.js**で`Sprite`を使う時は、以下の様な画像を使い、`frameIndex`を指定して表示していると思います。

![tomapiyo.png](https://qiita-image-store.s3.amazonaws.com/0/31052/bc587b2f-11c8-6acc-874e-019632ba4610.png)



１枚につき１キャラクタなら良いのですが、少し凝ったゲームを作るとキャラクタ数と同時に画像が増えて管理が煩雑になってきます。
理想としては、１枚（または複数）の画像に複数のキャラクタを乗せて、一部を切り取って表示させたい所です。
しかし、**32 x 32**と**48 x 48**みたいに異なるサイズのスプライト画像をまとめた場合、きちんと`setFrameIndex`で指定が出来る様に考えて画像を作らなければなりません。

調べた所、世の中には、テクスチャアトラスという物があって、テクスチャの一部を任意に指定して、スプライトを表示させる機能があるというではありませんか。
phina.jsでも似た事が出来ないかなと考えて、こんなのを作ってみました。

[サンプル(runstant)](http://runstant.com/minimo/projects/d7d2ace2)

#コードの説明
何をしているのかコードを見てみましょう。

最初に表示しているのは通常の使い方です。
読み込んだテクスチャを`frameIndex`を指定して、表示範囲も`Update`内で制御しています。

```JavaScript:ふつう
        //普通の使い方
        var tomapiko1 = phina.display.Sprite(texture, 64, 64);
        tomapiko1.addChildTo(that);
        tomapiko1.setPosition(400, 320);
        tomapiko1.setFrameIndex(15);
        tomapiko1.update = function(e) {
          this.frameIndex++;
          if (this.frameIndex === 0) this.frameIndex = 15;
        }
```


次に表示しているのは`setFrameTrimming`という関数を使用して、テクスチャの範囲を設定。
設定された範囲内で`frameIndex`を指定してスプライトを表示しています。

```JavaScript:ちょっと変えた
        //画像の使用範囲を指定する使い方
        var tomapiko2 = phina.display.Sprite(texture, 64, 64);
        tomapiko2.addChildTo(that);
        tomapiko2.setPosition(400, 450);

        //16～18コマの位置 x:192 y:128 を始点として、
        //横:192 縦:64をスプライト用画像とする
        tomapiko2.setFrameTrimming(192, 128, 192, 64);
        tomapiko2.setFrameIndex(0)

        tomapiko2.update = function(e) {
          this.frameIndex++;
        }
```


`setFrameTrimming`は通常のphina.jsの`Sprite`にはありません。
以下の様に用意しています。

```JavaScript:setFrameTrimming
phina.display.Sprite.prototype.setFrameTrimming = function(x, y, width, height) {
  this._frameTrimX = x || 0;
  this._frameTrimY = y || 0;
  this._frameTrimWidth = width || this.image.domElement.width - this._frameTrimX;
  this._frameTrimHeight = height || this.image.domElement.height - this._frameTrimY;
  return this;
}

phina.display.Sprite.prototype.setFrameIndex = function(index, width, height) {
  var sx = this._frameTrimX || 0;
  var sy = this._frameTrimY || 0;
  var sw = this._frameTrimWidth  || (this.image.domElement.width-sx);
  var sh = this._frameTrimHeight || (this.image.domElement.height-sy);

  var tw  = width || this.width;      // tw
  var th  = height || this.height;    // th
  var row = ~~(sw / tw);
  var col = ~~(sh / th);
  var maxIndex = row*col;
  index = index%maxIndex;

  var x   = index%row;
  var y   = ~~(index/row);
  this.srcRect.x = sx+x*tw;
  this.srcRect.y = sy+y*th;
  this.srcRect.width  = tw;
  this.srcRect.height = th;

  this._frameIndex = index;

  return this;
}
```

引数に始点の座標(x,y)、画像の縦横幅(width, height)を指定して使用します。

`setFrameTrimming`内で`_frameTrimX` `_frameTrimY` `_frameTrimWidth` `_frameTrimHeight`等の変数で使用して、スプライト表示範囲を指定しています。
それに伴い、`setFrameIndex`も変更を行っています。

これを使えば、大小異なる大きさの画像を一枚にまとめる事が出来るようになり、画像読み込みの時間も短縮できるようになります。


#おしまい
コードは[サンプル](http://runstant.com/minimo/projects/d7d2ace2)からコピペしてそのまま動作しますのでご自由にお使いください。
個人的によく使う機能なので、そのうちプルリクするかもしれません…しれません…

最初の構想では、[JSONでテクスチャアトラスを作成するサービス](https://minimo.github.io/TextureWrapper/)を作って、それに対応するクラスを作成するつもりだったのですが、時間が無くて中途半端な機能になってしまいました。
いずれ完成させて、**phina.js**から利用できるようにしたいと思ってます。
その時はまた記事書くのでよろしくお願いしますー。