この記事は、phina.js Advent Calendar 2016 12/3の記事です。
昨日 → phina.jsでbulletml.jsを使う! by daishi_hmrさん
明日 → phina+websocketの作る例 by tamochu3141さん
#はじめに
phina.jsでSprite
を使う時は、以下の様な画像を使い、frameIndex
を指定して表示していると思います。
1枚につき1キャラクタなら良いのですが、少し凝ったゲームを作るとキャラクタ数と同時に画像が増えて管理が煩雑になってきます。
理想としては、1枚(または複数)の画像に複数のキャラクタを乗せて、一部を切り取って表示させたい所です。
しかし、32 x 32と48 x 48みたいに異なるサイズのスプライト画像をまとめた場合、きちんとsetFrameIndex
で指定が出来る様に考えて画像を作らなければなりません。
調べた所、世の中には、テクスチャアトラスという物があって、テクスチャの一部を任意に指定して、スプライトを表示させる機能があるというではありませんか。
phina.jsでも似た事が出来ないかなと考えて、こんなのを作ってみました。
#コードの説明
何をしているのかコードを見てみましょう。
最初に表示しているのは通常の使い方です。
読み込んだテクスチャをframeIndex
を指定して、表示範囲もUpdate
内で制御しています。
//普通の使い方
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
を指定してスプライトを表示しています。
//画像の使用範囲を指定する使い方
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
にはありません。
以下の様に用意しています。
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
も変更を行っています。
これを使えば、大小異なる大きさの画像を一枚にまとめる事が出来るようになり、画像読み込みの時間も短縮できるようになります。
#おしまい
コードはサンプルからコピペしてそのまま動作しますのでご自由にお使いください。
個人的によく使う機能なので、そのうちプルリクするかもしれません…しれません…
最初の構想では、JSONでテクスチャアトラスを作成するサービスを作って、それに対応するクラスを作成するつもりだったのですが、時間が無くて中途半端な機能になってしまいました。
いずれ完成させて、phina.jsから利用できるようにしたいと思ってます。
その時はまた記事書くのでよろしくお願いしますー。