phina.jsで画像を表示してみる

2020年12月13日

画像を表示しよう

前回はチュートリアルの「図形を表示しよう」を試した。次は「画像を表示しよう」だ。ただ表示するだけだとつまらないので、ググる。

あった!ジャンプしたり向きを変えたりしてキャラクターが移動している。

次の画像を使っていた。

tomapiko_ss.png

フレームアニメーション情報(tomapiko.tmss)の中を覗いてみると次の表のようにアニメーションを定義しているようだ。

[0] stand[1] fly1[2] fly2[3] fly3[4] damage[5] die
[6] front1[7] front2,4[8] front3[9] back1[10] back2,4[11] back3
[12] left1[13] left2,4[14] left3[15] right1[16] right2,4[16] right3

tomapiko.tmss

{
  "frame": {
    "width": 64,
    "height": 64,
    "rows": 3,
    "cols": 6
  },
  "animations": {
    "stand": {
      "frames": [0],
      "next": "stand",
      "frequency": 4
    },
    "fly": {
      "frames": [1, 2, 3],
      "next": "fly",
      "frequency": 4
    },
    "front": {
      "frames": [6, 7, 8, 7],
      "next": "front",
      "frequency": 4
    },
    "back": {
      "frames": [9, 10, 11, 10],
      "next": "back",
      "frequency": 4
    },
    "left": {
      "frames": [12, 13, 14, 13],
      "next": "left",
      "frequency": 4
    },
    "right": {
      "frames": [15, 16, 17, 16],
      "next": "right",
      "frequency": 4
    },
    "damage": {
      "frames": [4]
    },
    "die": {
      "frames": [5]
    }
  }
}

damageとdieもかわいいので飛んでいるときに画面端に来たらdamageとdieにしてみた。

index.htmlはそのまま。

<!doctype html>

<html>
  <head>
    <meta charset='utf-8' />
    <meta name="viewport" content="width=device-width, user-scalable=no" />
    <meta name="apple-mobile-web-app-capable" content="yes" />

    <title>Getting started | phina.js</title>
    <!-- phina.js を読み込む -->
    <script src='https://cdn.jsdelivr.net/gh/phi-jp/phina.js@0.2.3/build/phina.js'></script>

    <!-- メイン処理 -->
    <script src='main.js'></script>
  </head>
  <body>

  </body>
</html>

main.jsにちょっとコードを加える。leftだけでrightは使ってないけどthis.scaleX *= -1;で反転させているようだ。

// グローバルに展開
phina.globalize();
// アセット
var ASSETS = {
  // 画像
  image: {
    'tomapiko': 'https://cdn.jsdelivr.net/npm/phina.js@0.2.3/assets/images/tomapiko_ss.png',
  },
  // フレームアニメーション情報
  spritesheet: {
    'tomapiko_ss': 'https://cdn.jsdelivr.net/npm/phina.js@0.2.3/assets/tmss/tomapiko.tmss',
  },
};
// 定数
var JUMP_POWOR = 10; // ジャンプ力
var GRAVITY = 0.5; // 重力
/*
 * メインシーン
 */
phina.define("MainScene", {
  // 継承
  superClass: 'DisplayScene',
  // コンストラクタ
  init: function() {
    // 親クラス初期化
    this.superInit();
    // 背景
    this.backgroundColor = 'skyblue';

    Label({
      text: 'Touch To Jump',
      fontSize: 48,
      fill: 'gray',
    }).addChildTo(this).setPosition(this.gridX.center(), this.gridY.span(3));
    // 床
    this.floor = RectangleShape({
      width: this.gridX.width,
      height: this.gridY.span(1),
      fill: 'silver',
    }).addChildTo(this).setPosition(this.gridX.center(), this.gridY.center(2));
    // プレイヤー作成
    var player = Player('tomapiko').addChildTo(this);
    // 初期位置
    player.x = this.gridX.center();
    player.bottom = this.floor.top;
    // 画面タッチ時処理
    this.onpointend = function() {
      // 床の上なら
      if (player.isOnFloor) {
        // 上方向に速度を与える(ジャンプ)
        player.physical.velocity.y = -JUMP_POWOR;
        // 重力復活
        player.physical.gravity.y = GRAVITY;
        // フラグ変更
        player.isOnFloor = false;
        // アニメーション変更
        player.anim.gotoAndPlay('fly');
      }
    };
    // 参照用
    this.player = player;
  },
  // 毎フレーム処理
  update: function() {
    var player = this.player;
    // 床とヒットしたら
    if (player.hitTestElement(this.floor)) {
      // y方向の速度と重力を無効にする
      player.physical.velocity.y = 0;
      player.physical.gravity.y = 0;
      // 位置調整
      player.bottom = this.floor.top;
      // フラグ立て
      player.isOnFloor = true;
      // アニメーション変更
      if (player.damage) {
        // ダメージ中に床とヒットしたらしばらくdie
        player.anim.gotoAndPlay('die');
        this.damageCount = 10;
      } else {
        player.anim.gotoAndPlay('left');
      }
    }
    // しばらくdieしたら復活
    if (this.damageCount > 0) {
        this.damageCount--;
        if (this.damageCount == 0) {
          player.anim.gotoAndPlay('left');
          player.damage = false;
        }
    }
  },
});
/*
 * プレイヤークラス
 */
phina.define('Player', {
  superClass: 'Sprite',
  // コンストラクタ
  init: function(image) {
    // 親クラス初期化
    this.superInit(image);
    // フレームアニメーションをアタッチ
    this.anim = FrameAnimation('tomapiko_ss').attachTo(this);
    // 初期アニメーション指定
    this.anim.gotoAndPlay('left');
    // 初速度を与える
    this.physical.force(-2, 0);
    // 床の上かどうか
    this.isOnFloor = true;
    // 端にぶつかる
    this.damage = false;
  },
  // 毎フレーム処理
  update: function() {
    // 画面端で速度と向き反転
    if (this.left < 0 || this.right > 640) {
      this.physical.velocity.x *= -1;
      this.scaleX *= -1;
      // 飛んでいるときに画面橋に来たらダメージ
      if (!this.isOnFloor && !this.damage) {
        this.anim.gotoAndPlay('damage');
        this.damage = true;
      }
    } 
  },
});
/*
 * メイン処理
 */
phina.main(function() {
  // アプリケーションを生成
  var app = GameApp({
    // MainScene から開始
    startLabel: 'main',
    // アセット読み込み
    assets: ASSETS,
  });
  // fps表示
  //app.enableStats();
  // 実行
  app.run();
});

See the Pen rNMLPKv by haku (@t-haku) on CodePen.

ここで動く。

基底クラス用途
DisplaySceneShapeやSpriteを表示できる。
Sprite画像配置やフレームアニメーションができる。