学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Rails7.0 | Railsでゲームを作成 | 17 | 魔法の実装

16 | 魔法使いのステータス】 << 【ホーム】 >> 【18 | スコアボード



↓↓クリックして頂けると励みになります。


魔法使いが、火の玉(ファイヤー)を飛ばすよう実装します。


「frontend/game.js」ファイルを編集します。


記述編集 【Desktop/RailsGame/frontend/game.js】

// initilize context
kaboom({
    scale: 3,
    width: 240,
    height: 160,
    background: [0, 0, 0],
    canvas: document.getElementById("screen"),
  });

const PLAYER_SPEED = 80;
const OGRE_SPEED = 30;

const WIZARD_SPEED = 20;
const FIRE_SPEED = 100;
 
loadSprite("floor", "/sprites/floor.png", { sliceX: 8 });
loadSprite("wall_left", "/sprites/wall_left.png");
loadSprite("wall_mid", "/sprites/wall_mid.png");
loadSprite("wall_right", "/sprites/wall_right.png");
loadSprite("wall_fountain", "/sprites/wall_fountain.png", {
    sliceX: 3,
    anims: {
      idle: { from: 0, to: 2, speed: 5, loop: true },
    },
  });

// プレイヤー
  loadSprite("knight", "/sprites/knight.png", {
    sliceX: 8,
    anims: {
        idle: { from: 0, to: 3, speed: 5, loop: true },
        run: { from: 4, to: 7, speed: 10, loop: true },
    },
});

// 敵
loadSprite("ogre", "/sprites/ogre.png", {
    sliceX: 8,
    anims: {
      run: { from: 0, to: 7, speed: 5, loop: true },
    },
  });

  // 罠
  loadSprite("spikes", "/sprites/spikes.png", {
    sliceX: 4,
    anims: {
      idle: { from: 0, to: 3, speed: 3, loop: true },
    },
  });

  // 落とし穴
  loadSprite("hole", "/sprites/hole.png", {
    sliceX: 2,
    anims: {
      open: { from: 0, to: 1, speed: 5, loop: false },
    },
  });

  // 宝箱
  loadSprite("chest", "/sprites/chest.png", {
    sliceX: 3,
    anims: {
      open: { from: 0, to: 2, speed: 20, loop: false },
      close: { from: 2, to: 0, speed: 20, loop: false },
    },
  });
  
  // 魔法使い
  loadSprite("wizard", "/sprites/wizard.png", {
    sliceX: 8,
    anims: {
      idle: { from: 0, to: 3, speed: 5, loop: true },
      run: { from: 4, to: 7, speed: 10, loop: true },
    },
  });  


scene("play", ({level}) => {
    // 10x10 半角スペース10
    addLevel(
      [
        "          ",
        "          ",
        "          ",
        "          ",
        "          ",
        "          ",
        "          ",
        "          ",
        "          ",
        "          ",
      ],
      {
        width: 16,
        height: 16,
        " ": () => [sprite("floor", { frame: ~~rand(0, 8) })],
      }
    )

    const mapConfig = {
        width: 16,
        height: 16,
        l: () => [sprite("wall_left"), area(), solid(), "wall"],
        r: () => [sprite("wall_right"), area(), solid(), "wall"],
        w: () => [sprite("wall_mid"), area(), solid(), "wall"],
        f: () => [
          sprite("wall_fountain", { anim: "idle" }),
          area(),
          solid(),
          "wall",
        ],
        // 敵
        "&": () => [
            sprite("ogre", { anim: "run" }),
            scale(0.75),
            area(),
            solid(),
            origin("center"),
            { dir: choose([-1, 1]), timer: 0 },
            "ogre",
            "danger",
        ],
        // 罠
        "^": () => [
            sprite("spikes", { anim: "idle" }), 
            area(), 
            "spikes", 
            "danger"
        ],
        // 落とし穴
        h: () => [
            sprite("hole"), 
            area(), 
            { opened: false }, 
            "hole"
        ],
    };

    // マップリスト
    const matrix = [
        [
          "lwwwffwwwr",
          "l        r",
          "l      & r",
          "l     ^  r",
          "l      & r",
          "l^       r",
          "l     &  r",
          "l h   ^  r",
          "l        r",
          "lwwwwwwwwr",
        ],
        [
            "lffffffffr",
            "l        r",
            "l        r",
            "l        r",
            "l        r",
            "l        r",
            "l        r",
            "l        r",
            "l        r",
            "lwwwwwwwwr",
        ],
    ];      

    // マップレベル
    map = addLevel(matrix[level], mapConfig);

    // ----- スコア表示 -----
    add([pos(200, 20), sprite("chest", { frame: 2 }), origin("center")]);
    add([pos(182, 30), text("Treasure"),scale(0.1),]);
    const scoreLabel = add([
      text("0"),
      pos(200, 45),
      { value: 0 },
      scale(0.3),
      origin("center"),
    ]);
    add([text("Player"), pos(200, 62), origin("center"), scale(0.08)]);
    add([text("Brave"), pos(200, 70), origin("center"), scale(0.15)]);
  

    // ----- プレイヤー -----
    const player = add([
        pos(map.getPos(2, 2)),
        sprite("knight", { anim: "idle" }),
        solid(), // 他のオブジェクトが移動できないようにします。
        //area(), // 形状からコライダーエリアを生成し、衝突検出を可能にします
        origin("center"),
        area({ width: 16, height: 16, offset: vec2(0, 8) }),

    ]);    

    // 敵やトラップに触るとプレイヤーが死ぬ
    player.onCollide("danger", async (d) => {
        shake(10);
        burp();
        addKaboom(player.pos);
        destroy(player);
        destroy(d);
    
        await wait(2);
        go("over", { score: scoreLabel.value });
      });
    
    onKeyDown("left", () => {
        player.flipX(true);
        player.move(-PLAYER_SPEED, 0);
    });
    onKeyDown("right", () => {
        player.flipX(false);
        player.move(PLAYER_SPEED, 0);
    });
    onKeyDown("up", () => {
        player.move(0, -PLAYER_SPEED);
    });
    onKeyDown("down", () => {
        player.move(0, PLAYER_SPEED);
    });

    onKeyPress(["left", "right", "up", "down"], () => {
        player.play("run");
    });

    // 止まっている時と動いている時のアニメーションを分ける
    onKeyRelease(["left", "right", "up", "down"], () => {
        if (
          !isKeyDown("left") &&
          !isKeyDown("right") &&
          !isKeyDown("up") &&
          !isKeyDown("down")
        )
        {
          player.play("idle");
        }
    });

    // 穴の上でスペースを押すとハシゴが出てLevel2マップに移動する
    onKeyPress("space", () => {

        //穴の動作
        every("hole", async (h) => {
            if (player.isTouching(h)) {
                if (!h.opened) {
                    h.play("open");
                    h.opened = true;

                    await wait(1);
                    go("play", { level: 1 });
                }
            }
        })

        //宝箱の動作
        every("chest", async (c) => {
          if (player.isTouching(c)) {
            if (!c.opened) {
              c.play("open");
              c.opened = true;
    
              scoreLabel.value++;
              scoreLabel.text = scoreLabel.value;
            }
          }
        });

    })

    // ----- 敵 -----
    // フレームごとに実行されるイベント (1 秒あたり 60 回)
    // 対象:敵タグを持つ全てのゲームオブジェクト
    onUpdate("ogre", (o) => {
      o.move(o.dir * OGRE_SPEED, 0);
      o.timer -= dt(); // カウントダウン

      if (o.timer <= 0) {
        o.dir = -o.dir;
        o.timer = rand(5);
      }
    });

  // -------------- ここから最終マップ(MAP LEVEL 2) ---------------
  if (level == 0) return;

  // ----- 宝箱 -----
  // 2秒ごとにランダムな位置に新しい宝箱を追加します。
  // そして4秒以内に消えます。
  loop(2, () => {
    const x = rand(1, 8);
    const y = rand(1, 8);

    add([
      sprite("chest"),
      pos(map.getPos(x, y)),
      area(),
      solid(),
      { opened: false },
      lifespan(4, { fade: 0.5 }), // 4 秒後に自動で破壊され、0.5 秒後にフェードアウトします。
      "chest",
    ]);
  });

  // ----- 魔法使い -----
  const wizard = add([
    sprite("wizard"),
    pos(map.getPos(8, 7)),
    origin("center"),
    area(),
    "danger",
    state("move", ["idle", "attack", "move"]),
  ]);

  // 「idle」状態に入るたびにコールバックを 1 回実行します
  wizard.onStateEnter("idle", async () => {
    wizard.play("idle");
    // ここでは 0.5 秒間「idle」状態を維持し、その後「移動」状態に入ります。
    await wait(0.5);
    wizard.enterState("attack");
  });

  // 「attack」状態に入るたびにコールバックを 1 回実行します
  wizard.onStateEnter("attack", async () => {
    if (player.exists()) {
      const dir = player.pos.sub(wizard.pos).unit();

      // ファイヤー
      add([
        pos(wizard.pos),
        move(dir, FIRE_SPEED),
        rect(2, 2),
        area(),
        origin("center"),
        color(RED),
        cleanup(), // ファイヤーが画面外に出た場合はクリーンアップ
        "fire",
        "danger",
      ]);
    }

    await wait(1);
    wizard.enterState("move");
  });

  // 「move」状態に入るたびにコールバックを 1 回実行します
  wizard.onStateEnter("move", async () => {
    wizard.play("run");
    await wait(2);
    wizard.enterState("idle");
  });

  wizard.onStateUpdate("move", () => {
    if (!player.exists()) return;

    const dir = player.pos.sub(wizard.pos).unit();
    wizard.flipX(dir.x < 0);
    wizard.move(dir.scale(WIZARD_SPEED));
  });

  wizard.enterState("move");

});


/**
 * --------------------
 * シーン: ゲームオーバー
 * --------------------
 */

scene("over", ({ score }) => {
    add([text(score, 26), origin("center"), pos(width() / 2, height() / 2)]);
    
    onMousePress(() => {
        go("play", { level: 0 });
    });
  });
  

go("play", { level: 1 });

//デバッグモード
//debug.inspect = true;



魔法使いがファイヤーを出すようになりました。
ブラウザで動作を確認してください。
http://127.0.0.1:5500/

魔法「ファイヤー」
魔法「ファイヤー」



↓↓クリックして頂けると励みになります。


16 | 魔法使いのステータス】 << 【ホーム】 >> 【18 | スコアボード