LoginSignup
10
11

More than 3 years have passed since last update.

Phina.JSでゲームを作ってみた

Last updated at Posted at 2019-10-07

Phina.JSで簡単なゲームを作ってみました

JavaScriptベースのゲームエンジンであるPhina.JSを使用した簡単なゲームを作ってみましたので、その作成手順をステップバイステップで説明します。 なお、Windows10の環境において Microsoft Edge (Ver. 11.0.17763.379), Firefox (Ver. 65.0.2/64 bit) 及び Google Chrome (Ver. 73.0.3683.86/64 bit) で動作を確認しました。 また、AndroidやiOSでもバージョンによっては動作可能です。
また、ここで使用しているグラフィックの一部に「​どらぴか様」ならびに「ぴぽや様」作成の素材をサウンドエフェクトには「小森平様」作成の素材を使用させていただきました。 フリー素材を提供して下さった各位に感謝いたします。

ファイル構成

ここで説明する内容に関するファイルは全て「GitHub PhinaJS_Sample_games」からダウンロード可能です。 また、そのファイル構成は次の通りです。
・ images: ゲームで使用するグラフィックを収納するフォルダーです。
・ js: 各ステップ毎のメイン・プログラムであるJavaScriptを収納するフォルダーです。
 - maze_02.js: Step-7で使用する迷路作成プログラムです。
 - phina.js, phina.min.js: Phina.JSゲームエンジン本体です。(Phina.JSからダウンロードしたもの)
 - phina_sample_01.js ~ phina_sample_09_with_sound_effect.js: 各ステップ毎のゲーム・プログラムです。
 - stages_01.js, stages_02.js: Step-5以降で使用するステージ用データで、stage_01.jsは敵がいないバージョン、stage_02.jsは敵がいるバージョンです。
・ sound: ゲームで使用するサウンド・エフェクトを収納するフォルダーです。
・ index_Phina_01.html ~ index_Phina_09_with_sound_effect.html: 各ステップ毎のゲーム開始用HTMLファイルです。

ゲーム作成の説明

以下にゲーム作成の手順をステップバイステップで説明します。

Step-1: 静止画グラフィックスを表示させる

始めにHTMLファイルを示します。 Phina.JSゲームエンジンの読込及びゲーム本体のJavaScriptファイルの読込等を行い全てのステップでほぼ同一ですが、各ステップ毎にタイトルと「src='./js/phina_sample_01.js'」の部分を変更しています。
Step-1のデモ実行

index_Phina_01.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>Sample for phina.js #001 by T. Fujita on 2019/9/12</title>
    <!-- phina.js を読み込む -->
    <script src='./js/phina.js'></script>

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

  </body>
</html>

次にメインプログラムである「phina_sample_01.js」を示します。 背景画像とグラフックス(player)を読み込み表示します。

phina_sample_01.js
/*
 * phina.js sample #001 by T. Fujita on 2019/9/12
 */

phina.globalize();

var SCREEN_X = 800;
var SCREEN_Y = 600;
var scale = 1;
var P_size = 48 * scale;

var ASSETS = {
  image: {
    'Player': './images/ETNR_TOMITA_01.png',
    'bg': './images/bg.jpg',
  },
};

phina.define('MainScene', {
  superClass: 'DisplayScene',

  init: function(option) {
    this.superInit(option);
    this.bg = Sprite("bg").addChildTo(this);
    this.bg.origin.set(0, 0);
    this.bg.width = SCREEN_X;
    this.bg.height = SCREEN_Y;
//    this.backgroundColor = '#ffaaaa';
    var player = Sprite('Player', 48, 48)
    .addChildTo(this)
    .setPosition(this.gridX.center(), this.gridY.center())
    .setScale(scale);
    player.frameIndex = 0;
  },
});

phina.main(function() {
  var app = GameApp({
    startLabel: 'main',
    width: SCREEN_X,
    height: SCREEN_Y,
    assets: ASSETS,
  });

  app.run();
});

Step-2: 静止画グラフィックスを移動させてみる

前述の「phina_sample_01.js」にマウスをクリックした位置あるいはキー入力の検知を追加し、それに合わせてplayerを移動させるものが「phina_sample_02.js」です。 追加・修正個所を以下に示します。
Step-2のデモ実行

phina_sample_02.js(追加・修正部分)
  update: function(app) {
    var keyboard = app.keyboard;
    var touch_p = app.pointer;

    // 左右移動
    if (keyboard.getKey('left') || (touch_p.getPointing() && (Math.floor(this.player.x / Step) * Step) > (Math.floor(touch_p.x / Step) * Step))) {
      this.player.x -= Step;
    if(this.player.x < (P_size / 2)) {
        this.player.x = P_size / 2;
    }
    }
    if (keyboard.getKey('right') || (touch_p.getPointing() && (Math.floor(this.player.x / Step) * Step) < (Math.floor(touch_p.x / Step) * Step))) {
      this.player.x += Step;
    if(this.player.x > (SCREEN_X - P_size / 2)) {
        this.player.x = SCREEN_X - P_size / 2;
    }
    }
    // 上下移動
    if (keyboard.getKey('up') || (touch_p.getPointing() && (Math.floor(this.player.y / Step) * Step) > (Math.floor(touch_p.y / Step) * Step))) {
      this.player.y -= Step;
    if(this.player.y < (P_size / 2)) {
        this.player.y = P_size / 2;
    }
    }
    if (keyboard.getKey('down') || (touch_p.getPointing() && (Math.floor(this.player.y / Step) * Step) < (Math.floor(touch_p.y / Step) * Step))) {
      this.player.y += Step;
    if(this.player.y > (SCREEN_Y - P_size / 2)) {
        this.player.y = SCREEN_Y - P_size / 2;
    }
    }
  }

Step-3: アニメーション・グラフィックスを表示させる

「phina_sample_01.js」を元にplayerをアニメーションさせる「phina_sample_03.js」を作成します。 変更部分を次に示します。 Phina.JSでは、RPGツクール等の歩行グラフィックスが使用可能です。
Step-3のデモ実行

phina_sample_03.js(追加分)
var ASSETS = {
  image: {
    'Player': './images/ETNR_TOMITA_01.png',
    'bg': './images/bg.jpg',
  },
  spritesheet: {
    'Player_ss':
    {
      'frame': {
    'width': 48,
    'height': 48,
    'cols': 12,
    'rows': 1,
      },
      'animations': {
    'down': {
      'frames': [0, 1, 2],
      'next': 'down',
      'frequency': F_rate,
    },
      }
    },
  }
};

phina.define('MainScene', {
  superClass: 'DisplayScene',

  init: function(option) {
    this.superInit(option);
    this.bg = Sprite("bg").addChildTo(this);
    this.bg.origin.set(0, 0);
    this.bg.width = SCREEN_X;
    this.bg.height = SCREEN_Y;
//    this.backgroundColor = '#ffaaaa';
    var player = Sprite('Player', P_size, P_size).addChildTo(this)
    .setPosition(this.gridX.center(), this.gridY.center())
    .setScale(scale);
    var anim_p = FrameAnimation('Player_ss').attachTo(player);
    anim_p.gotoAndPlay('down');
  },
});

Step-4: アニメーション・グラフィックスを移動させてみる

前述の「phina_sample_02.js」と「phina_sample_03.js」を組み合わせて前後(上下)左右の歩行アニメーションを追加したものが「phina_sample_04.js」です。 追加分の一部として左右歩行部分を以下に示します。
Step-4のデモ実行

phina_sample_04.js(追加・修正の一部分)
  update: function(app) {
    var keyboard = app.keyboard;
    var touch_p = app.pointer;

// 左右移動
    if (keyboard.getKey('left') || (touch_p.getPointing() && (Math.floor(this.player.x / Step) * Step) > (Math.floor(touch_p.x / Step) * Step))) {
      this.player.x -= Step;
      if(app.frame % F_rate === 0) {
    this.player.frameIndex = (this.player.frameIndex === 3) ? 5:3;
      }
    }
    else if (keyboard.getKey('right') || (touch_p.getPointing() && (Math.floor(this.player.x / Step) * Step) < (Math.floor(touch_p.x / Step) * Step))) {
      this.player.x += Step;
      if(app.frame % F_rate === 0) {
    this.player.frameIndex = (this.player.frameIndex === 6) ? 8:6;
      }
    }

Step-5: 壁等を表示させ、移動を制限する

「phina_sample_04.js」に「stages_01.js」で設定する各ステージを読み込みタイルデータを表示させたものが「phina_sample_05.js」です。 ここでは、壁を通り抜け出来ない設定とゴール、再度実行(Aタイル)のみ対応するようにしています。
Step-5のデモ実行

phina_sample_05.js(タイルデータ表示部分)
    if(counter >= max_rooms) {
    counter = 0;
    this.exit();
    }
    ROOM = room[counter];
    counter = counter + 1;

    this.player = Sprite('Player', 48, 48).addChildTo(this).setScale(scale);
    this.player.frameIndex = 0;
    this.wall_0Group = DisplayElement().addChildTo(this);
    this.wall_1Group = DisplayElement().addChildTo(this);

    for (i=0; i<ROOM.length; i++) {
    temp[i] = [];
    for (j=0; j<ROOM[i].length; j++) {
        temp[i][j] = ROOM[i].substr(j,1);
        if(ROOM[i].substr(j,1) == "P") { 
        this.player.setPosition( j * P_size + P_size/2, i * P_size + P_size/2); 
        }
        else if(ROOM[i].substr(j,1) == "A") { 
        this.again = Again().addChildTo(this).setScale(scale);
        this.again.setPosition( j * P_size + P_size/2, i * P_size + P_size/2); 
        }
        else if(ROOM[i].substr(j,1) == "G") { 
        var goal = Goal().addChildTo(this).setScale(scale);
        goal.setPosition( j * P_size + P_size/2, i * P_size + P_size/2); 
        }
        else if(ROOM[i].substr(j,1) == "B") { 
        BLOCK[BL_counter] = Block().addChildTo(this).setScale(scale);
        BLOCK[BL_counter].setPosition( j * P_size + P_size/2, i * P_size + P_size/2); 
        BL_counter = BL_counter + 1;
        }
        else if(ROOM[i].substr(j,1) == "w") { 
        var wall_0 = Wall_0().addChildTo(this.wall_0Group).setScale(scale); 
        wall_0.setPosition( j * P_size + P_size/2, i * P_size + P_size/2); 
        }
        else if(ROOM[i].substr(j,1) == "W") { 
        var wall_1 = Wall_1().addChildTo(this.wall_1Group).setScale(scale); 
        wall_1.setPosition( j * P_size + P_size/2, i * P_size + P_size/2); 
        }
    }
    }
phina_sample_05.js(左側の壁対応部分)
    if (flag == "left") {
        player.x -= Step;
        if(app.frame % F_rate === 0) {
        player.frameIndex = (player.frameIndex === 3) ? 5:3;
        }
        if((pos[p_x - 1][p_y] == "W") || pos[p_x - 1][p_y] == "w") {
        if(player.x < (p_x) * P_size + P_size/2 + Step) {
            player.x = (p_x) * P_size + P_size/2;
        }
        } else if(pos[p_x - 1][p_y] != "G") {
        pos[p_x][p_y] = "F";
        pos[p_x - 1][p_y] = "P";
        }
    } else if (flag == "right") {
phina_sample_05.js(ゴール対応部分と再度実行部分)
    if(pos[p_x][p_y] == "G") {
    END_falg = "Goal !";
    this.nextLabel ="title";
    this.exit();
    }
    again.setInteractive(true);
    again.onpointstart = function () {
    END_flag = "Again";
    }
    if(END_flag == "Again") {
    this.nextLabel ="title";
    this.exit();
    }

各ステージを構成する「stage_01.js」の一部を以下に示します。 メモ帳等のエディターで修正・追加してみてください。

stage_01.js
// All the rooms are here. 
// by T. Fujita
// 
// A: Again
// B: Block(Movable)
// F: Floor
// G: Goal
// P: Player
// W: Wall

var room = [];
    room[0] = [ "WwwwwGwW",
        "WFFFFFFW",
        "WFFFFFFW",
        "WFPFFFFW",
        "WFFFFFFW",
        "WwwwwwwA"]

    room[1] = [ "WwwwwGwW",
        "WFFFFBFW",
        "WFFFFFFW",
        "WFPFFFFW",
        "WFFFFFFW",
        "WwwwwwwA"]

    room[2] = [ "WwwwwwwwwwwwwGwW",
        "WFFFFFFFFFFFFFFW",
        "WBBBBBBBBBBBBBBW",
        "WFFFFFFFFFFFFFFW",
        "WFFFFFFFFFFFFFFW",
        "WFFFFFFFFFFFFFFW",
        "WFFFFFFFFFFFFFFW",
        "WFFFFFFFFFFFFFFW",
        "WFFPFFFFFFFFFFFW",
        "WFFFFFFFFFFFFFFW",
        "WFFFFFFFFFFFFFFW",
        "WwwwwwwwwwwwwwwA"]

Step-6: ボックスを押して移動可能にさせる

「phina_sample_06.js」でplayerがBoxを押して移動できるようにしました。 これでゲームの基本部分は完成です。
Step-6のデモ実行

phina_sample_06.js(左側の壁対応にBOX移動を追加した部分)
    if (flag == "left") {
        player.x -= Step;
        if(app.frame % F_rate === 0) {
        player.frameIndex = (player.frameIndex === 3) ? 5:3;
        }
        if((pos[px - 1][py] == "W") || pos[px - 1][py] == "w") {
        if(player.x < px * P_size + Step) {
            player.x = px * P_size;
        }
        } else if(pos[px - 1][py] == "B") {
        for(i=0; i<BL_counter; i++) {
            if((Math.round(BLOCK[i].x / P_size) == (px - 1)) && (Math.round(BLOCK[i].y / P_size) == py)) {
            BL_temp = i;
            BL_x = BLOCK[i].x;
            BL_y = BLOCK[i].y;
            }
        }
        if(pos[px - 2][py] == "F") {
            if(player.x < BL_x + P_size + Step) {
            BLOCK[BL_temp].x = (px - 2) * P_size;
            if(pos[px][py] == "P") {pos[px][py] = "F";}
            if(pos[px - 1][py] == "B") {pos[px - 1][py] = "P";}
            if(pos[px - 2][py] == "F") {pos[px - 2][py] = "B";}
            }
        } else {
            if(player.x <= BL_x + P_size - Step) {
            player.x = px * P_size;
            if(pos[px][py] == "F") {pos[px][py] = "P";}
            }
        }
        } else if(pos[px - 1][py] != "G") {
        if(pos[px][py] == "F") {pos[px][py] = "P";}
        }
        if(pos[px + 1][py - 1] == "P") {pos[px + 1][py - 1] = "F";}
        if(pos[px + 1][py] == "P") {pos[px + 1][py] ="F";}
        if(pos[px + 1][py + 1] == "P") {pos[px + 1][py + 1] = "F";}
    } else if (flag == "right") {

さらにゴール時の効果音を追加しました。 「phina_sample_06_with_sound_effect.js」でゴール時に効果音を作動させます。
Step-6効果音付きのデモ実行

phina_sample_06_with_sound_effect.js(ゴール時の効果音を追加したASSETS部分)
var ASSETS = {
  image: {
    'bg': './images/bg.jpg',
    'Player': './images/ETNR_TOMITA_01.png',
    'again': './images/A_48.png',
    'block': './images/Box_06.png',
    'goal': './images/Goal_00.png',
    'wall_0': './images/Block_05.png',
    'wall_1': './images/Block_04.png',
  },
  sound: {
    'GOAL': './sound/crrect_answer3.mp3',
  },
};
phina_sample_06_with_sound_effect.js(ゴール時の効果音を鳴らす部分を追加した箇所)
    if(pos[p_x][p_y] == "G") {
    END_falg = "Goal !";
    SoundManager.play('GOAL');
    this.nextLabel ="title";
    this.exit();
    }

Step-7: 迷路を作成しアニメーション・グラフィックスを移動させてみる

「phina_sample_06_with_sound_effect.js」を若干変更し、「maze_02.js」で作成した迷路を表示させたものが「phina_sample_07_with_sound_effect.js」です。 各グラフィックスのサイズは1/2に設定しています。 迷路は、「Algoful : Algorithm for making a maze」のアルゴリズムを使用させていただきました。
Step-7のデモ実行

maze_02.js
// This program is based on "http://algoful.com/Archive/Algorithm/MazeDig" by Algoful.
// by T. Fujita

var maze = [];
var startCells = [];

var Maze = function(X, Y) 
{
    var w = X;                                  // 幅(奇数)
    var h = Y;                                  // 高さ(奇数)
    if(w < 11) {w = 11;}
    if(h < 11) {h = 11;}
    if(w % 2 == 0) {w = w - 1;}
    if(h % 2 == 0) {h = h - 1;}

    var x;
    var y;
    var results = [];

    var currentCells = [];

    for (x = 0; x < w; x++) {
    maze[x] = new Array();
    for (y = 0; y < h; y++) {
            if (x == 0 || y == 0 || x == w - 1 || y == h - 1) {
                maze[x][y] = "F";                       // 外周を通路に設定
            } else {
        maze[x][y] = "W";                       // 残りを壁に設定
        }
    }
    }

    startCells[0] = [];
    startCells[0][0] = (Math.floor(Math.random() * (w / 2 - 2))) * 2 + 1;
    startCells[0][1] = (Math.floor(Math.random() * (h / 2 - 2))) * 2 + 1;

    Dig(startCells[0][0], startCells[0][1]);

    for (x = 0; x < w; x++)
    {
    for (y = 0; y < h; y++)
    {
        if (x == 0 || y == 0 || x == w - 1 || y == h - 1)
        {
        maze[x][y] = "W";                       // 外周を壁に戻す
        }
    }
    }
    let i = 0;
    while (maze[i][1] == "W") {
    if(maze[i + 1][1] == "F") {
        maze[i + 1][1] = "P";
        break;
    }
    i = i + 1;
    }
    i = maze.length - 2;
    let j = maze[0].length - 1;
    while(maze[i][j] == "W") {
    if(maze[i - 1][j - 1] == "F") {
        maze[i - 1][j] = "G";
        break;
    }
    i = i - 1;
    }
    for (y = 0; y < h; y++) {
    results[y] = [];
    for (x = 0; x < w; x++) {
        results[y] = results[y] + maze[x][y];
    }
    }
// alert(results[0] + "\n" + results[1]);
    return results;
}


function Dig(x, y) 
{
  while (true) {
    var directions = [];
    if(maze[x][y-1] == "W" && maze[x][y-2] =="W") {directions.push("UP");}
    if(maze[x][y+1] == "W" && maze[x][y+2] =="W") {directions.push("DOWN");}
    if(maze[x-1][y] == "W" && maze[x-2][y] =="W") {directions.push("LEFT");}
    if(maze[x+1][y] == "W" && maze[x+2][y] =="W") {directions.push("RIGHT");}
    if(directions.length == 0) {break;}
    var rnd = Math.floor(Math.random() * directions.length);
    switch (directions[rnd])
    {
    case 'UP':
        SetPath(x, --y);
            SetPath(x, --y);
            break;
        case 'DOWN':
            SetPath(x, ++y);
            SetPath(x, ++y);
            break;
        case 'LEFT':
            SetPath(--x, y);
            SetPath(--x, y);
            break;
        case 'RIGHT':
            SetPath(++x, y);
            SetPath(++x, y);
            break;
    }
// console.log(maze[0] + "\n" + maze[1] + "\n" + maze[2] + "\n" + maze[3] + "\n" + maze[4] + "\n" + maze[5]);
    var cell = GetStartCell();
    if(cell != null)
    {
    Dig(cell[0], cell[1]);
    }
  }
}


function SetPath(x, y) 
{
    maze[x][y] = "F";
    if((x % 2 == 1) && (y % 2 == 1))
    {
    var Temp = [x, y];
    startCells.push(Temp);
    }
}


function GetStartCell()
{
    if(startCells.length == 0) {return null;}
    var rnd = Math.floor(Math.random() * startCells.length);
    var cell = startCells[rnd];
    startCells.splice(rnd, 1);
    return cell;
}

Step-8: 敵を出現させる

追加として、「phina_sample_06_with_sound_effect.js」に敵(gost)を出現させランダムに移動させてみたものが「phina_sample_08_with_sound_effect.js」です。 もちろんplayerが敵と当たればGame Overとなります。 なお、敵の出現数・位置は「stage_02.js」での"E"文字で設定しており、壁やBOXと同様に表示させています。
Step-8のデモ実行

phina_sample_08_with_sound_effect.js(敵の出現・移動部分)
    for(var k = 0; k < EN_counter; k++) {
        EN_x[ k ] = Math.floor(ENEMY[ k ].x / P_size);
        EN_y[ k ] = Math.floor(ENEMY[ k ].y / P_size);
        EC_x[ k ] = Math.ceil(ENEMY[ k ].x / P_size);
        EC_y[ k ] = Math.ceil(ENEMY[ k ].y / P_size);
        var Temp = Math.random() * 5;
        if(Temp < 1 && EN_flag[ k ] == "stay") {
        EN_flag[ k ] = "left";
        EN_temp[ k ] = 0;
        }
        else if(Temp < 2 && EN_flag[ k ] == "stay") {
        EN_flag[ k ] = "right";
        EN_temp[ k ] = 0;
        }
        else if(Temp < 3 && EN_flag[ k ] == "stay") {
        EN_flag[ k ] = "up";
        EN_temp[ k ] = 0;
        }
        else if(Temp < 4 && EN_flag[ k ] == "stay") {
        EN_flag[ k ] = "down";
        EN_temp[ k ] = 0;
        }
        else {

        }

    if(EN_flag[ k ] == "left") {
        if(pos[EC_x[ k ] - 1][EN_y[ k ]] == "F") {
            EN_temp[ k ] += 1;
            ENEMY[ k ].x -=Step;
            if(app.frame % F_rate === 0) {
                ENEMY[ k ].frameIndex = (ENEMY[ k ].frameIndex === 3) ? 5:3;
            }
            if(EN_temp[ k ] >= P_size/Step) {
            EN_flag[ k ] = "stay";
            }
        } else {
            EN_flag[ k ] = "stay";
        }
    }
    if(EN_flag[ k ] == "right") {
        if(pos[EN_x[ k ] + 1][EN_y[ k ]] == "F") {
            EN_temp[ k ] += 1;
            ENEMY[ k ].x +=Step;
            if(app.frame % F_rate === 0) {
                ENEMY[ k ].frameIndex = (ENEMY[ k ].frameIndex === 6) ? 8:6;
            }
            if(EN_temp[ k ] >= P_size/Step) {
            EN_flag[ k ] = "stay";
            }
        } else {
            EN_flag[ k ] = "stay";
        }
    }
    if(EN_flag[ k ] == "up") {
        if(pos[EN_x[ k ]][EC_y[ k ] - 1] == "F") {
            EN_temp[ k ] += 1;
            ENEMY[ k ].y -=Step;
            if(app.frame % F_rate === 0) {
                ENEMY[ k ].frameIndex = (ENEMY[ k ].frameIndex === 9) ? 11:9;
            }
            if(EN_temp[ k ] >= P_size/Step) {
            EN_flag[ k ] = "stay";
            }
        } else {
            EN_flag[ k ] = "stay";
        }
    }
    if(EN_flag[ k ] == "down") {
        if(pos[EN_x[ k ]][EN_y[ k ] + 1] == "F") {
            EN_temp[ k ] += 1;
            ENEMY[ k ].y +=Step;
            if(app.frame % F_rate === 0) {
                ENEMY[ k ].frameIndex = (ENEMY[ k ].frameIndex === 0) ? 2:0;
            }
            if(EN_temp[ k ] >= P_size/Step) {
            EN_flag[ k ] = "stay";
            }
        } else {
            EN_flag[ k ] = "stay";
        }
    }
    if(EN_flag[ k ] == "stay") {

    }

    for(var m=0; m<EN_counter; m++) {
        if(player.hitTestElement(ENEMY[ m ])) {
        END_flag = "Game Over !";
        SoundManager.play('GAMEOVER');
        this.nextLabel ="title";
        this.exit();
        }
    }
    }

Step-9: 敵をBOXで潰すことができるようにする

さらに敵をBOXで潰すことができるようにしました。 左側での対処プログラムを以下にしまします。
Step-9のデモ実行

phina_sample_09_with_sound_effect.js(敵をBOXで潰す/左側対応部分)
    if(EN_flag[ k ] == "left") {
        ENEMY[ k ].frameIndex = 3;
        if(pos[EC_x[ k ] - 1][EN_y[ k ]] == "F") {
        EN_temp[ k ] += 1;
        ENEMY[ k ].x -=Step;
        if(app.frame % F_rate === 0) {
            ENEMY[ k ].frameIndex = (ENEMY[ k ].frameIndex === 3) ? 5:3;
        }
        if(EN_temp[ k ] >= P_size/Step) {
            EN_flag[ k ] = "stay";
        }
        }
        else if((pos[EN_x[ k ]][EN_y[ k ]] == "B") && (pos[EN_x[ k ] - 1][EN_y[ k ]] != "F")) {
        EN_temp = k;
        ENEMY[ EN_temp ].tweener.fadeOut(1000).call(function(){
            ENEMY[ EN_temp ].remove();
            ENE_flag = 1;
        }).play();
        } else {
        EN_flag[ k ] = "stay";
        }
    }
    else if(EN_flag[ k ] == "right") {

Reference

  1. github Cocos2d_Sample_games
  2. Home Page of Cocos2d-x
  3. Download page for Cocos2d-JS
  4. Home Page of PIKA's GAME
  5. Home Page of Pipoya
  6. Algoful : Algorithm for making a maze
  7. 無料効果音で遊ぼう!

おまけ

JavaScriptベースのゲームエンジンは他にも多数ありますが、その内の幾つかで同様のゲームを作成してみました。 ソースファイルを覘くとゲームエンジン別の特徴がうかがえるかと思います。

以上

10
11
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
10
11