JavaScript»ゲーム制作»clickイベント トランプをめくる(全カード)

ファイル名: js-game/quest_00729.html

下のプログラムをうつして、縦横たてよこにならべて表示ひょうじされたトランプカードのうちクリックされたカードがおもてを向くようにしてください。画像がぞうは下のリンクからダウンロードできます。

画像をダウンロード

ソースコード

class Card {

  constructor(image, num, mark) {
    this.image = image;
    this.num = num;
    this.mark = mark;
    this.x = 0;
    this.y = 0;
    this.opened = false; // 最初は裏向き
  }

  // このカードの表示位置(左上頂点)を指定したx, yに設定する
  setLocation(x, y) {
    this.x = x;
    this.y = y;
  }

  // x, yで指定された点がこのカードの表示領域内であれば、カードを開いた状態にする
  openIfContains(x, y) {
    if (x > this.x && x < this.x + 32 && y > this.y && y < this.y + 64) {
      this.opened = true;
    }
  }

  update() {
    // 特に自動的に変化するデータはない
  }

  render(context) {
    const trimX = this.opened ? this.num * 32 : 448;
    const trimY = this.opened ? this.mark * 64 : 128;
    context.drawImage(this.image, trimX, trimY, 32, 64, this.x, this.y, 32, 64);
  }
}

// 52枚のCardオブジェクトがはいったデッキを表すクラス
class CardDeck {

  constructor(image) {
    this.cards = [];
    for (let num = 0; num < 13; num++) {
      for (let mark = 0; mark < 4; mark++) {
        this.cards.push(new Card(image, num, mark));
      }
    }
  }

  // デッキ内のCardをシャッフルする
  shuffle() {
    for (let i = this.cards.length - 1; i > 0; i--) {
      const r = Math.floor(Math.random() * (i + 1));
      const tmp = this.cards[i];
      this.cards[i] = this.cards[r];
      this.cards[r] = tmp;
    }
  }

  // カードデッキから、nで指定した枚数のCardオブジェクトを配列で取り出す
  pop(n) {
    const cards = [];
    for (let i = 0; i < n; i++) {
      cards.push(this.cards.pop());
    }
    return cards;
  }
}

const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");

const image = new Image();
image.src = "cards.png";
image.addEventListener("load", () => {

  const deck = new CardDeck(image);
  deck.shuffle();
  const cards = deck.pop(52);

  cards.forEach((card, i) => {
    const x = (i % 13) * 32 + 32;
    const y = Math.floor(i / 13) * 64 + 32;
    card.setLocation(x, y);
  });

  canvas.addEventListener("click", (e) => {
    const rect = e.target.getBoundingClientRect();
    const x = e.clientX - rect.left - 1;
    const y = e.clientY - rect.top - 1;
    cards.forEach(card => card.openIfContains(x, y));
  });

  const FPS = 20;
  const frameTime = 1 / FPS;
  let prevTimestamp = 0;

  const update = (timestamp) => {

    const elapsed = (timestamp - prevTimestamp) / 1000;
    if (elapsed <= frameTime) {
      requestAnimationFrame(update);
      return;
    }

    prevTimestamp = timestamp;

    cards.forEach(card => card.update());
    context.clearRect(0, 0, 320, 320);
    cards.forEach(card => card.render(context));
    requestAnimationFrame(update);
  };

  update();
});

解説

各クラスは「トランプをめくる((横一列))」と同じですね。ちがうところは77~81行目です。

popメソッドで52枚すべてを取り出して配列にしています。そして、横に13枚並ぶようにx,yを設定しています。