JavaScript»体験講座 体験講座 ゲームをつくろう もぐらたたき編(ゲームエンジン使用)

ファイル名: js-trial/quest_01109.html

タイトル画面の作成

タイトル画面を表示します。

// スタートボタン
class StartButton extends Actor {

  constructor() {
    super(110, 150, new Rect(0, 0, 100, 25));
    this.w = 100;
    this.h = 25;
  }

  render(context) {
    context.fillStyle = "#fff";
    context.font = "25px monospace";
    context.textAlign = "center"
    context.fillText("START", 160, this.y + this.h);
  }
}

// タイトル画面
class MoguTitleScene extends Scene {

  constructor() {
    super();
    this.startButton = new StartButton();
    this.add(this.startButton);
  }

  renderBackground(context) {
    super.renderBackground(context);
    context.fillStyle = "#000";
    context.fillRect(0, 0, this.game.width, this.game.height);
  }
}

// ゲームスタート
window.onload = () => {
  const game = new Game("もぐらたたき", 320, 345, 60);
  game.loadAssets().then(() => {
    game.changeScene(new MoguTitleScene());
    game.start();
  });
};

STARTボタンを押したらゲーム画面に変わる

ゲーム画面と、背景画像を用意して、

// ゲームスタートの手前にこれを追加
class MoguMainScene extends Scene {

  constructor(backgroundImage) {
    super();
    this.backgroundImage = backgroundImage;
  }

  renderBackground(context) {
    super.renderBackground(context);
    context.drawImage(this.backgroundImage, 0, 25, 320, 320);
  }
}

// ゲームスタート
window.onload = () => {
  const game = new Game("もぐらたたき", 320, 345, 60);
  // 画像読込
  game.addImage("bg", "bg.png");
  game.loadAssets().then(() => {
...

STARTボタンがクリックされたときにゲーム画面に切り替えます。

class StartButton extends Actor {

  constructor() {
    super(110, 150, new Rect(0, 0, 100, 25));
    this.w = 100;
    this.h = 25;
  }

  // スタートボタンにこれを追加
  onClick(game, x, y) {
    if (!this.startedAt) {
      this.startedAt = this.tick;
    }
  }

  // これも追加
  update(game, input) {
    if (this.startedAt) {
      game.changeScene(new MoguMainScene(game.image.bg));
    }
  }

...

モグラをランダムに出現させる

12匹のモグラを用意し、並べます。

  render(context) {
    context.fillStyle = "#fff";
    context.font = "25px monospace";
    context.textAlign = "center"
    context.fillText("START", 160, this.y + this.h);
  }
}

// スタートボタンの下にこれを追加
class Mogu extends Actor {

  constructor(image, x, y) {
    super(x, y, new Rect(0, 0, 80, 85));
    this.image = image;
    this.visible = false;
  }

  update(game, input) {
    if (game.tick % game.fps === 0) {
      this.visible = Math.random() >= 0.7;
    }
  }

  render(context) {
    if (!this.visible) {
      return;
    }
    const x = 0;
    const y = 0;
    context.drawImage(this.image, x, y, 80, 85, this.x, this.y, 80, 85);
  }
}
class MoguMainScene extends Scene {

  constructor(backgroundImage) {
    super();
    this.backgroundImage = backgroundImage;
  }

  // MoguMainSceneの中にこれを追加
  onStart(game) {
    for (let i = 0; i < 12; i++) {
      const x = (i % 4) * 80;
      const y = Math.floor(i / 4) * 85 + 85;
      const mogu = new Mogu(game.image.mogu, x, y);
      this.add(mogu);
    }
  }

...
window.onload = () => {
  const game = new Game("もぐらたたき", 320, 345, 60);
  game.addImage("bg", "bg.png");
  // モグラ画像読込
  game.addImage("mogu", "mogu.png");
  game.loadAssets().then(() => {
    game.changeScene(new MoguTitleScene());
    game.start();
  });
};

たたかれたモグラを泣かす

class Mogu extends Actor {

  constructor(image, x, y) {
    super(x, y, new Rect(0, 0, 80, 85));
    this.image = image;
    // これを追加
    this.hit = false;
    this.visible = false;
  }

  // これを追加
  onClick(game, x, y) {
    if (this.visible && !this.hit) {
      this.hit = true;
      this.dispatchEvent("hit", new GameEvent(this));
    }
  }

  update(game, input) {
    if (game.tick % 60 === 0) {
      // これを追加
      this.hit = false;
      this.visible = Math.random() >= 0.7;
    }
  }

  render(context) {
    if (!this.visible) {
      return;
    }
    // ここを変更
    const x = this.hit ? 80 : 0;
    const y = 0;
    context.drawImage(this.image, x, y, 80, 85, this.x, this.y, 80, 85);
  }
}

スコアをつける

  render(context) {
    if (!this.visible) {
      return;
    }
    const x = this.hit ? 80 : 0;
    const y = 0;
    context.drawImage(this.image, x, y, 80, 85, this.x, this.y, 80, 85);
  }
}

// Moguの下にこれを追加
class ScoreLabel extends Actor {

  constructor(x, y) {
    super(x, y);
    this.score = 0;
  }

  addScore(mogu) {
    this.score += 10;
  }

  render(context) {
    context.fillStyle = "rgb(0, 0, 0)";
    context.font = "23px monospace";
    context.fillText("SCORE: " + this.score, this.x, this.y);
  }
}
  onStart(game) {

    // MoguMainSceneのonStartの中にこれを追加
    this.scoreLabel = new ScoreLabel(0, 20);
    this.add(this.scoreLabel);

    for (let i = 0; i < 12; i++) {
      const x = (i % 4) * 80;
      const y = Math.floor(i / 4) * 85 + 85;
      const mogu = new Mogu(game.image.mogu, x, y);
      // これも追加
      mogu.addEventListener("hit", e => this.scoreLabel.addScore(e.target));
      this.add(mogu);
    }
  }

モグラをたたいたときの効果音をならす

window.onload = () => {
  const game = new Game("もぐらたたき", 320, 345, 60);
  game.addImage("bg", "bg.png");
  game.addImage("mogu", "mogu.png");
  // 効果音の読込. hit01.mp3 ~ hit09.mp3 まで、好きなのを使ってね
  game.addAudio("hit", "hit09.mp3", 5);
  game.loadAssets().then(() => {
...
  onClick(game, x, y) {
    if (this.visible && !this.hit) {
      // MoguのonClickの中にこれを追加
      game.audio.hit.play(0.2);
      this.hit = true;
      this.dispatchEvent("hit", new GameEvent(this));
    }
  }

BGMをならす

window.onload = () => {
  const game = new Game("もぐらたたき", 320, 345, 60);
  game.addImage("bg", "bg.png");
  game.addImage("mogu", "mogu.png");
  game.addAudio("hit", "hit09.mp3", 5);
  // BGMの読込. bgm01.mp3 ~ bgm04.mp3 まで、好きなのを使ってね
  game.addAudio("bgm", "bgm01.mp3");
  game.loadAssets().then(() => {
...
  onClick(game, x, y) {
    if (!this.startedAt) {
      this.startedAt = this.tick;
      // StartButtonのonClickの中にこれを追加
      game.loadAudios();
    }
  }
  onStart(game) {

    // MoguMainSceneのonStartの中にこれを追加
    game.audio.bgm.playEndless(0.2);
    
    this.scoreLabel = new ScoreLabel(0, 20);
    this.add(this.scoreLabel);

ときどきレアモグラを出現させる

class Mogu extends Actor {

  constructor(image, x, y) {
    super(x, y, new Rect(0, 0, 80, 85));
    this.image = image;
    this.hit = false;
    this.visible = false;
    // これを追加
    this.rare = false;
  }

  // 中略

  update(game, input) {
    if (game.tick % game.fps === 0) {
      this.hit = false;
      this.visible = Math.random() >= 0.7;
      // これを追加. 0.99以上になる確率は1%. 0.99を別の値に変えたらレア出現率が変わる
      this.rare = Math.random() >= 0.99;
    }
  }

  render(context) {
    if (!this.visible) {
      return;
    }
    const x = this.hit ? 80 : 0;
    // ここを変更. 85を170や255にするとレアモグラの色が変わる
    const y = this.rare ? 85 : 0;
    context.drawImage(this.image, x, y, 80, 85, this.x, this.y, 80, 85);
  }
}
class ScoreLabel extends Actor {

  constructor(x, y) {
    super(x, y);
    this.score = 0;
  }

  addScore(mogu) {
    // ここを変更. 500はレアモグラをたたいたときの点数
    this.score += mogu.rare ? 500 : 10;
  }

...

※ このサンプルで使用したオーディオファイルは下記サイトからお借りしました。