Pixi.js でパララックススクローラーを作ってみる【第三回】

前回の話

前回は初回で作ったもののリニューアルです。見た目や動き自体変わりがありません。
今回はチュートリアルのpart2の続きです。今まで作ってきたものをメソード化していきます。

Building a Parallax Scroller with Pixi.js: Part 2

続き

先ほどFarとMidはPIXI.extras.TilingSprite.prototypeから引き継いだので、今の全体像はこうなってます。
f:id:manmanrai:20170429202045p:plain そしてコードの全体はこんな感じです。

var Container = PIXI.Container,
    autoDetectRenderer = PIXI.autoDetectRenderer,
    loader = PIXI.loader;

var renderer = autoDetectRenderer(512, 384, {antialiasing: true}),
    stage = new Container();
document.body.appendChild(renderer.view);

loader
    .add(['images/bg-far.png', 'images/bg-mid.png'])
    .load(setup);
var far, mid;

function setup(){
  far = new Far();
  stage.addChild(far);

  mid = new Mid();
  stage.addChild(mid);

  requestAnimationFrame(update);
}

function update(){

  far.update();
  mid.update();

  renderer.render(stage);

  requestAnimationFrame(update);
}

function Far(){
    var texture = PIXI.Texture.fromImage("images/bg-far.png");
    PIXI.extras.TilingSprite.call(this,texture, 512, 256);
    this.position.x = 0;
    this.position.y = 0;
    this.tilePosition.x = 0;
    this.tilePosition.y = 0;
}

Far.prototype = Object.create(PIXI.extras.TilingSprite.prototype);
Far.prototype.update = function(){
    this.tilePosition.x -= 0.128;
};

function Mid(){
    var texture = PIXI.Texture.fromImage("images/bg-mid.png");
    PIXI.extras.TilingSprite.call(this,texture, 512, 256);
    this.position.x = 0;
    this.position.y = 128;
    this.tilePosition.x = 0;
    this.tilePosition.y = 0;
}

Mid.prototype = Object.create(PIXI.extras.TilingSprite.prototype);
Mid.prototype.update = function(){
    this.tilePosition.x -= 0.64;
};

次はスクローラー自体をクラス化していきます。

function Scroller(stage) {
}

このクラス自体には二つの問題が存在しています。まず、rendererへに繋がってないこと、二つ目は、どのプロトタイプから引き継いでないこと。
MidとFarを利用してアウトプットできるように導入します。

function Scroller(stage) {

  this.far = new Far();
  stage.addChild(this.far);

  this.mid = new Mid();
  stage.addChild(this.mid);
}

そしてupdateもScroller functionの後に追加します。

Scroller.prototype.update = function() {
  this.far.update();
  this.mid.update();
};

前のsetup functionをこのように書き換えられます。
midとfarに対しての操作じゃなくなるってことですね。

function setup(){
  //far = new Far();
  //stage.addChild(far);

  //mid = new Mid();
  //stage.addChild(mid);
  scroller = new Scroller(stage);

  requestAnimationFrame(update);
}

同じ今までmidとfarこの二つを操作してたupdate functionもこう書き換えます。

function update(){

  //far.update();
  //mid.update();
  scroller.update();

  renderer.render(stage);

  requestAnimationFrame(update);
}

ブラウザ開くと、動作変わりがないのかもう一回確認します。問題なければ次へ進みます。

Viewport表示域

まず、ScrollerのupdateをsetViewportXに書き換えます。

function Scroller(stage) {
  this.far = new Far();
  stage.addChild(this.far);

  this.mid = new Mid();
  stage.addChild(this.mid);
}

// Scroller.prototype.update = function() {
//   this.far.update();
//   this.mid.update();
// };
Scroller.prototype.setViewportX = function(viewportX) {
  this.far.setViewportX(viewportX);
  this.mid.setViewportX(viewportX);
};

次はFarとMidのupdateも書き換えます。

function Far() {
  var texture = PIXI.Texture.fromImage("resources/bg-far.png");
  PIXI.extras.TilingSprite.call(this, texture, 512, 256);

  this.position.x = 0;
  this.position.y = 0;
  this.tilePosition.x = 0;
  this.tilePosition.y = 0;
 
  // 追加する
  this.viewportX = 0;
}

Far.prototype = Object.create(PIXI.extras.TilingSprite.prototype);

// Far.prototype.update = function() {
//   this.tilePosition.x -= 0.128;
// };

// 追加する
Far.DELTA_X = 0.128;
Far.prototype.setViewportX = function(newViewportX) {
  var distanceTravelled = newViewportX - this.viewportX;
  this.viewportX = newViewportX;
  this.tilePosition.x -= (distanceTravelled * Far.DELTA_X);
};

最後にupdate functionにも更新します。

function update() {
  // scroller.update();

  renderer.render(stage);

  requestAnimationFrame(update);
}

ブラウザを開くとアニメーション効果がなくなり、静止画面になってます。
そこでコンソール開きます。

scroller.setViewportX(50);

入れると、画像が少しずらしたこと分かります。

scroller.setViewportX(7000);

setViewportXをScrollerに任せる

先までx軸の値はMidとかFarで初期設定しましたが、今度からはscrollerで操作するように変えていきます。

function Scroller(stage) {
  this.far = new Far();
  stage.addChild(this.far);

  this.mid = new Mid();
  stage.addChild(this.mid);

  // 追加する
  this.viewportX = 0;
}

Scrollerのupdateにも

Scroller.prototype.setViewportX = function(viewportX) {
  // 追加する
  this.viewportX = viewportX;

  this.far.setViewportX(viewportX);
  this.mid.setViewportX(viewportX);
};

そして、Scrollerのprototypeもう一個追加します。

Scroller.prototype.getViewportX = function() {
  return this.viewportX;
};

次はupdate function内部で

function update(){

  // 追加する
  var newViewportX = scroller.getViewportX() + 5;
  scroller.setViewportX(newViewportX);
  // 追加する

  renderer.render(stage);
  requestAnimationFrame(update);
}

ブラウザ開くと結構早めなスピードで動いています。
最後にさっき追加したものをprototypeとしてScrollerの下に付けます。

Scroller.prototype.moveViewportXBy = function(units) {
  var newViewportX = this.viewportX + units;
  this.setViewportX(newViewportX);
};

そして、updateにそう書き換えます。

function update() {
  // var newViewportX = scroller.getViewportX() + 5;
  // scroller.setViewportX(newViewportX);
  scroller.moveViewportXBy(5);

  renderer.render(stage);

  requestAnimationFrame(update);
}

コード全体的に簡潔ように見えてきました。
part2意外に長かったのです、読むだけでも結構時間かかりました。

次はpart3向かって進みたいと思います。
ではまた次回で。