Chapter 01

ピースの配置

alkn203
alkn203
2022.11.14に更新

はじめに

この本では、メジャーなスライドパズルである15パズルphina.jsで作った過程を解説します。

今回の目標

以下のように、15パズルのピースを配置します。

15puzzle-tut-1.png

完成コード

今回の完成コードは、以下のとおりです。

コードを見る
// グローバルに展開
phina.globalize();
// 定数
var SCREEN_WIDTH = 640;            // 画面横サイズ
var SCREEN_HEIGHT = 960;           // 画面縦サイズ
var GRID_SIZE = SCREEN_WIDTH / 4;  // グリッドのサイズ
var PIECE_SIZE = GRID_SIZE * 0.95; // ピースの大きさ
var PIECE_NUM_XY = 4;              // 縦横のピース数
var PIECE_OFFSET = GRID_SIZE / 2;  // オフセット値
/*
 * メインシーン
 */
phina.define('MainScene', {
  superClass: 'DisplayScene',
  // コンストラクタ
  init: function() {
    // 親クラス初期化
    this.superInit();
    // 背景色
    this.backgroundColor = 'gray';
    // グリッド
    var grid = Grid(SCREEN_WIDTH, PIECE_NUM_XY);
    // ピースグループ
    var pieceGroup = DisplayElement().addChildTo(this);
    // ピース配置
    PIECE_NUM_XY.times(function(spanX) {
      PIECE_NUM_XY.times(function(spanY) {
        // ピース作成
        var piece = Piece().addChildTo(pieceGroup);
        // Gridを利用して配置
        piece.x = grid.span(spanX) + PIECE_OFFSET;
        piece.y = grid.span(spanY) + PIECE_OFFSET;
      });
    });
  },
});
/*
 * ピースクラス
 */
phina.define('Piece', {
  // RectangleShapeを継承
  superClass: 'RectangleShape',
    // コンストラクタ
    init: function() {
      // 親クラス初期化
      this.superInit({
        width: PIECE_SIZE,
        height: PIECE_SIZE,
        cornerRadius: 10,
        fill: 'silver',
        stroke: 'white',
      });
    },
});
/*
 * メイン処理
 */
phina.main(function() {
  // アプリケーションを生成
  var app = GameApp({
    // MainScene から開始
    startLabel: 'main',
  });
  // 実行
  app.run();
});

runstantプロジェクト

https://runstant.com/alkn203/projects/bf291944

コード説明

定数の定義

メインシーンの前にピースサイズなどを定数として定義します。

// 定数
var SCREEN_WIDTH = 640;            // 画面横サイズ
var SCREEN_HEIGHT = 960;           // 画面縦サイズ
var GRID_SIZE = SCREEN_WIDTH / 4;  // グリッドのサイズ
var PIECE_SIZE = GRID_SIZE * 0.95; // ピースの大きさ
var PIECE_NUM_XY = 4;              // 縦横のピース数
var PIECE_OFFSET = GRID_SIZE / 2;  // オフセット値

ピースクラスの定義

後々の利便性を考え、phina.defineで以下のようにクラス化します。

// ピースクラス
phina.define('Piece', {
  // RectangleShapeを継承
  superClass: 'RectangleShape',
    // コンストラクタ
    init: function() {
      // 親クラス初期化
      this.superInit({
        width: PIECE_SIZE,
        height: PIECE_SIZE,
        cornerRadius: 10,
        fill: 'silver',
        stroke: 'white',
      });
    },
});
  • Pieceクラスはphina.jsで最初から用意されているRectangleShape(矩形)クラスを継承し、init関数内で親クラス(RectangleShape)にパラメータを渡して初期化しています。
  • ピースは正方形ですので、widthheightには同じPIECE_SIZEを与えています。
  • cornerRadiusプロパティを設定することで、角丸の四角形にすることができます。
  • fillは塗りつぶしの色、strokeは枠の色です。
  • phina.jsには他にも円や三角形などのShape(基本図形)が用意されており、どれも最小限のパラメータで描画することができるので、簡単な動作確認の際に重宝します。

ピースの配置

今回の目的であるピースの配置について説明します。

// グリッド
var grid = Grid(SCREEN_WIDTH, PIECE_NUM_XY);
// ピースグループ
var pieceGroup = DisplayElement().addChildTo(this);
// ピース配置
PIECE_NUM_XY.times(function(spanX) {
  PIECE_NUM_XY.times(function(spanY) {
    // ピース作成
    var piece = Piece().addChildTo(pieceGroup);
    // Gridを利用して配置
    piece.x = grid.span(spanX) + PIECE_OFFSET;
    piece.y = grid.span(spanY) + PIECE_OFFSET;
  });
});
  • 画面幅をピースの並び数で区割りしたGridを作成しています。
  • DisplayElementクラスを使って、pieceGroupという名前のグループを作っています。
  • ピースの配置は2重ループ処理で行いますが、今回は、phina.js独自のtimesメソッドを使用しています。PIECE_NUM_XYには4という数値が入っていますので、引数で与えられたfunction内の処理を4回繰り返すという意味になります。spanXspanYには、インデックス値である0~3の数値がループ処理で入ってきますので、これを利用します。
  • 次にピースを作成して、先に作ったpieceGroupに追加しています。
  • 最後に、グリッドを利用してピースを配置しています。定数の定義部分でグリッドのサイズよりピースのサイズを少し小さくしていますが、これによりpaddingに似た効果を得ることができます。なお、phina.jsでのオブジェクトの座標値はオブジェクトの原点(デフォルトではオブジェクトの中心)となりますので、PIECE_OFFSETで位置を調整しています。PIECE_OFFSETの箇所を削除して実行してみると、結果の違いが分かるかと思います。
  • 作成したpieceGroupMainSceneaddChildToすることで、ピースが画面に表示されます。