9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

phina.jsでオリジナルのローディングシーンを作る

Last updated at Posted at 2017-12-02

phina.jsバージョン: v0.2.1

はじめに

この記事はphina.js Advent Calendar 2017 Advent Calendar 2017の2日目です。
アドカレの最初の方なので(?)ローディングシーンについての話です。

GameAppクラスでオプションとしてassetsを渡した状態でアプリを実行すると、最初のシーンに移行する前にアセット類をロードするため、ローディングシーンを介すようになります。
上部に水色のバーが表示されるアレです。

phina.globalize();
phina.main(function() {
  var app = GameApp({
    startLabel: 'main',
    // 以下を設定してるとロードを挟む
    assets: {
      image: {
        logo: 'http://cdn.rawgit.com/phi-jp/phina.js/develop/logo.png',
      }
    },
  });

  app.run();
});

loading-example.png

改造するのはちょっと面倒くさい印象があったのですが、実は割りと簡単に自作することができると最近知りました。

こんなのとか

手順

元々定義されているLoadingSceneクラスをオーバーライドすることで、自作のものを使うよう仕向けることができます。
そして以下が最もシンプルな形となります。

// ※globalizeしてる場合は単に"LoadingScene"
phina.define('phina.game.LoadingScene', {
  superClass: 'phina.display.DisplayScene',

  init: function(options) {
    this.superInit(options);
    var self = this;
    var loader = phina.asset.AssetLoader();

    // ローダーによるロード完了ハンドラ
    loader.onload = function() {
      // Appコアにロード完了を伝える(==次のSceneへ移行)
      self.flare('loaded');
    };

    // ロード開始
    loader.load(options.assets);
  },

});

問題なく動きますが何も表示されないので寂しく、ユーザビリティ的にもアレです。(ローディングを意識させたくないときは有効ですが)

とりあえずラベルを足してみます。

// ~省略
init: function(options) {
  this.superInit(options);
  var self = this;
  this.backgroundColor = "#B8F7F6"; // 見辛いので背景色を変えます
  var loader = phina.asset.AssetLoader();

  // 明滅するラベル
  var label = phina.display.Label({
    text: "NOW LOADING...",
  })
  .addChildTo(this)
  .setPosition(this.width/2, this.height*0.2)
  label.tweener.clear()
  .setLoop(1)
  .to({alpha:0}, 500)
  .to({alpha:1}, 500)
  ;
  
  // ローダーによるロード完了ハンドラ
  loader.onload = function() {
    // Appにロード完了を伝える(=次のSceneへ移行)
    self.flare('loaded');
  };

  // ロード開始
  loader.load(options.assets);
},
// ~省略

少しそれっぽくなったかと思います。
(ロードするデータ量が少ないと一瞬すぎて分からないですが)

ロード進捗に応じて何かする

デフォルトのローディングシーンではプログレスバーによって進捗状況が分かるようになっていますね。

これはloaderがロードの進行に応じてprogressイベントを発火するので、それをトリガーに処理を行うことで実現しています。
またprogressイベントは引数で進捗具合を0 ~ 1の小数で返してくれます。

進行状況に応じてラベルのテキスト内容を変えてみましょう。

init: function(options) {
  this.superInit(options);
  var self = this;
  this.backgroundColor = "#B8F7F6";
  var loader = phina.asset.AssetLoader();

  // 明滅するラベル
  var label = phina.display.Label({
    text: "NOW LOADING...",
  })
  .addChildTo(this)
  .setPosition(this.width/2, this.height*0.2)
  label.tweener.clear()
  .setLoop(1)
  .to({alpha:0}, 500)
  .to({alpha:1}, 500)
  ;

  // ロードが進行したときの処理
  loader.onprogress = function(e) {
    // 進捗具合を%で表示する
    label.text = "ロード中… {0}%".format((e.progress * 100).toFixed(0));
  };
  
  // ローダーによるロード完了ハンドラ
  loader.onload = function() {
    // Appにロード完了を伝える(=次のSceneへ移行)
    self.flare('loaded');
  };

  // ロード開始
  loader.load(options.assets);
};

myloading-example2.png

(一瞬すぎて分かりづらい)サンプルコードです

アセットロード後のポスト処理

前述のように、loaderによるロードが完了してもscene自体のloadedイベントを発火しない限り、処理は進みません。
つまりアセットロード後に何か追加で処理を行うことも可能です。

例えば、ロード済みテクスチャにフィルターをかけたいときは以下のようになります。

// ~省略
var self = this;
var AssetManager = phina.asset.AssetManager;

// loaderによるロード後の処理
var afterLoad = function() {
  // グレスケ化フィルターを掛ける
  var filtered = AssetManager.get('image', 'player').clone().filter(function(pixel, i, x, y, imageData) {
    if (pixel[3] === 0) return;

    var Y = 0.299 * pixel[0] + 0.587 * pixel[1] + 0.114 * pixel[2];
    imageData.data[i] = Y; // r
    imageData.data[i+1] = Y; // g
    imageData.data[i+2] = Y; // b
  },)

  // フィルター後のテクスチャ登録
  AssetManager.set('image', 'player_gs', filtered);

  self.flare('loaded');
};

loader.onload = afterLoad;

// ~省略

複雑になりそうならFlowクラス(もしくはしPromise)を併用したり、ロード後の処理を別の関数に切り分けたりしましょう。

まとめ

  • まずLoadingSceneを上書き、assetLoaderにオプションを渡してロード開始
  • ロード進捗はprogressで、終了はended
  • 最後はthis.flare('loaded')

ローディングシーンは何気にタイトルシーンよりも先にプレイヤーが目にする部分だったりするため、侮れないところがあります。
余裕があればぜひ手を加えてみましょう。

9
5
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
9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?