Copilotにピンボールを作ってもらったらブロック崩しができた


2024/12/30の作業メモ

## 状況
- 開発端末のWindowsアップデートしたらCopilotが出現。
- せっかくなので「p5jsでピンボール作って」ってお願いしたら、ブロック崩しが出来上がった( ﾟДﾟ)


## デモ
＃キーボード操作前提のゲームです。雰囲気はスマホでも確認可能です。

https://kubo-4ka.github.io/p5breakout/

## ソース

https://github.com/kubo-4ka/p5breakout

## 会話履歴

```
サインイン
あなたの発言
どういったことができるのでしょうか？
```

```
Copilot の発言
たくさんのことをお手伝いできますよ！例えば：

質問に回答: 何か知りたいことがあれば、どんな質問でもお答えします。

アイデア出し: 創造的なプロジェクトや新しい趣味のアイデアを一緒に考えます。

サポートとアドバイス: 日常生活のヒントや技術的なサポートまで、いろいろなアドバイスができます。

会話とユーモア: リラックスしたいときや楽しい話がしたいときに、一緒にお話しましょう。
時々ユーモアも交えて。

こんな感じで、あなたの知識を広げたり、日常のサポートをしたりすることができます。
どうぞお気軽に話しかけてくださいね！
```


```
あなたの発言
p5jsでピンボールゲームを作成したいと考えているのですが、サンプルを作成いただけますでしょうか？
```

```
Copilot の発言
もちろんです！
p5.jsで基本的なピンボールゲームのサンプルコードを作成してみました。
以下のコードを使って、カスタマイズして楽しんでみてください。
```

<details><summary>javascript</summary>

javascript

コピー

let ball;
let paddles = [];
let walls = [];
let score = 0;

function setup() {
  createCanvas(600, 400);
  ball = new Ball();
  paddles.push(new Paddle(width / 2 - 50, height - 20, 100, 10));
  walls.push(new Wall(0, 0, 10, height));
  walls.push(new Wall(width - 10, 0, 10, height));
  walls.push(new Wall(0, 0, width, 10));
}

function draw() {
  background(0);
  
  ball.update();
  ball.show();
  
  for (let paddle of paddles) {
    paddle.show();
    if (ball.hits(paddle)) {
      ball.bounce();
      score += 10;
    }
  }
  
  for (let wall of walls) {
    wall.show();
    if (ball.hits(wall)) {
      ball.bounce();
    }
  }
  
  fill(255);
  textSize(16);
  text("Score: " + score, 10, 30);
  
  if (ball.offScreen()) {
    textSize(32);
    text("Game Over", width / 2 - 80, height / 2);
    noLoop();
  }
}

function keyPressed() {
  if (keyCode === LEFT_ARROW) {
    paddles[0].move(-10);
  } else if (keyCode === RIGHT_ARROW) {
    paddles[0].move(10);
  }
}

class Ball {
  constructor() {
    this.pos = createVector(width / 2, height / 2);
    this.vel = createVector(3, 3);
    this.r = 12;
  }

  update() {
    this.pos.add(this.vel);
  }

  show() {
    fill(255);
    ellipse(this.pos.x, this.pos.y, this.r * 2);
  }

  bounce() {
    this.vel.y *= -1;
  }

  hits(paddle) {
    let d = dist(this.pos.x, this.pos.y, paddle.pos.x + paddle.w / 2, paddle.pos.y);
    return (d < this.r + paddle.h / 2);
  }

  offScreen() {
    return (this.pos.y > height);
  }
}

class Paddle {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
  }

  show() {
    fill(255);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }

  move(step) {
    this.pos.x += step;
    this.pos.x = constrain(this.pos.x, 0, width - this.w);
  }
}

class Wall {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
  }

  show() {
    fill(255);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }

  hits(ball) {
    let d = dist(ball.pos.x, ball.pos.y, this.pos.x + this.w / 2, this.pos.y + this.h / 2);
    return (d < ball.r + min(this.w, this.h) / 2);
  }
}
</details>

```
このサンプルでは、ボールが自動的に動き、壁やパドルに当たると跳ね返る基本的なピンボールゲームが含まれています。
矢印キーでパドルを左右に動かせます。
カスタマイズして、自分だけのピンボールゲームを楽しんでください！
```


```
あなたの発言
簡単にコードを解説いただけますでしょうか？
```


```
Copilot の発言
もちろんです！
以下がサンプルコードの解説です：

グローバル変数の定義:

ball, paddles, walls, score が定義されています。
それぞれボール、パドル、壁、およびスコアを表しています。

setup関数:

createCanvas(600, 400) でキャンバスのサイズを設定。

ボール (ball) を新規作成。

パドル (paddles) を一つ追加、これがプレイヤーが操作する部分。

左、右、および上の壁 (walls) を追加。

draw関数:

background(0) で背景を黒くリセット。

ボールの動作と表示 (ball.update(), ball.show())、
パドルと壁の表示 (paddle.show(), wall.show())。

ボールがパドルや壁に衝突したかどうかをチェックし、
衝突した場合はボールの方向を変更 (ball.bounce())。

スコアの表示 (text("Score: " + score, 10, 30))。

ボールが画面外に出た場合にゲームオーバーの表示をし、
ゲームを停止 (noLoop())。

keyPressed関数:

左右の矢印キーを押すことで、パドルが左右に動く (paddles[0].move())。

Ballクラス:

ボールの位置 (pos)、速度 (vel)、半径 (r) を定義。

ボールの更新 (update)、表示 (show)、衝突した場合の反発 (bounce)、
パドルや壁との衝突検知 (hits)、
画面外に出たかどうかをチェック (offScreen)。

Paddleクラス:

パドルの位置 (pos)、幅 (w)、高さ (h) を定義。

パドルの表示 (show)、移動 (move)。

Wallクラス:

壁の位置 (pos)、幅 (w)、高さ (h) を定義。

壁の表示 (show) とボールとの衝突検知 (hits)。

このコードはピンボールゲームの基本的な部分をカバーしており、
プレイヤーがパドルを操作してボールを壁と衝突させないようにします。
自由にカスタマイズして、より楽しいゲームを作ってみてください！
何か他に質問があれば、どうぞお知らせください。
```


```
あなたの発言
ありがとうございます。
動かしてみて分かったのですが、これはピンボールというよりは、ブロック崩しのようです。
また、キーリピートが上手く実装されていないようで、左右のキーを連打しないといけない状態です。
また、壁の当たり判定がうまくいっていないようで、
パドルで打ち返して斜めに右側の壁に当たった際、ゲーム画面外へ行ってしまいました。
ブロック崩しはブロック崩しで作りたいと思っていましたので改修してみたいのですが、
上記の問題について修正案をいただけますでしょうか？
```


```
Copilot の発言
ご指摘ありがとうございます！
ブロック崩しとして動作させるため、いくつかの修正を加えましょう。
まず、キーリピートの問題を解決し、パドルのスムーズな動作を実現します。
また、壁の当たり判定を改良します。

キーリピートの修正:
keyPressedとkeyReleased関数を使って、パドルの移動をスムーズにしましょう。

壁の当たり判定の修正:
壁の当たり判定を改善するため、壁との衝突時に適切な反発を行うようにします。

以下が改良されたコードです：
```

<details><summary>javascript</summary>

javascript

コピー
let ball;
let paddles = [];
let walls = [];
let score = 0;
let leftPressed = false;
let rightPressed = false;

function setup() {
  createCanvas(600, 400);
  ball = new Ball();
  paddles.push(new Paddle(width / 2 - 50, height - 20, 100, 10));
  walls.push(new Wall(0, 0, 10, height)); // 左の壁
  walls.push(new Wall(width - 10, 0, 10, height)); // 右の壁
  walls.push(new Wall(0, 0, width, 10)); // 上の壁
}

function draw() {
  background(0);

  ball.update();
  ball.show();

  for (let paddle of paddles) {
    paddle.show();
    if (ball.hitsPaddle(paddle)) {
      ball.bounceOffPaddle();
      score += 10;
    }
  }

  for (let wall of walls) {
    wall.show();
    if (ball.hitsWall(wall)) {
      ball.bounceOffWall(wall);
    }
  }

  // スムーズなパドル移動
  if (leftPressed) {
    paddles[0].move(-10);
  } else if (rightPressed) {
    paddles[0].move(10);
  }

  fill(255);
  textSize(16);
  text("Score: " + score, 10, 30);

  if (ball.offScreen()) {
    textSize(32);
    text("Game Over", width / 2 - 80, height / 2);
    noLoop();
  }
}

function keyPressed() {
  if (keyCode === LEFT_ARROW) {
    leftPressed = true;
  } else if (keyCode === RIGHT_ARROW) {
    rightPressed = true;
  }
}

function keyReleased() {
  if (keyCode === LEFT_ARROW) {
    leftPressed = false;
  } else if (keyCode === RIGHT_ARROW) {
    rightPressed = false;
  }
}

class Ball {
  constructor() {
    this.pos = createVector(width / 2, height / 2);
    this.vel = createVector(3, 3);
    this.r = 12;
  }

  update() {
    this.pos.add(this.vel);
  }

  show() {
    fill(255);
    ellipse(this.pos.x, this.pos.y, this.r * 2);
  }

  bounceOffPaddle() {
    this.vel.y *= -1;
  }

  hitsPaddle(paddle) {
    return (
      this.pos.y + this.r > paddle.pos.y &&
      this.pos.x > paddle.pos.x &&
      this.pos.x < paddle.pos.x + paddle.w
    );
  }

  bounceOffWall(wall) {
    if (wall.w > wall.h) {
      this.vel.y *= -1;
    } else {
      this.vel.x *= -1;
    }
  }

  hitsWall(wall) {
    return (
      this.pos.x + this.r > wall.pos.x &&
      this.pos.x - this.r < wall.pos.x + wall.w &&
      this.pos.y + this.r > wall.pos.y &&
      this.pos.y - this.r < wall.pos.y + wall.h
    );
  }

  offScreen() {
    return (this.pos.y > height);
  }
}

class Paddle {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
  }

  show() {
    fill(255);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }

  move(step) {
    this.pos.x += step;
    this.pos.x = constrain(this.pos.x, 0, width - this.w);
  }
}

class Wall {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
  }

  show() {
    fill(255);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }
}
</details>

```
この改良版では、以下の点が改善されています：

キーリピートの問題を解消し、パドルがスムーズに移動できるようになりました。

壁の当たり判定を改善し、ボールが画面外に飛び出さないようにしました。

ブロック崩しの部分もこのコードをベースに追加していくことができます。
さらに改良が必要な場合は、お知らせください！
どんな質問でもお答えします。
```


```
あなたの発言
ありがとうございます。
思った通りの動きとなりました！
改善点について、コードを説明いただけますでしょうか？
```

```
Copilot の発言
もちろんです！改善点について詳しく説明します。

キーリピートの修正
以前の実装:
以前のコードでは、keyPressed関数でパドルの移動を制御していました。
しかし、この方法ではキーを連打しなければパドルがスムーズに移動しませんでした。

javascript

コピー
function keyPressed() {
  if (keyCode === LEFT_ARROW) {
    paddles[0].move(-10);
  } else if (keyCode === RIGHT_ARROW) {
    paddles[0].move(10);
  }
}
改善後の実装:
キーが押され続けている間はパドルが連続して動くようにするために、
keyPressedとkeyReleased関数でフラグを設定し、
draw関数でフラグに基づいてパドルを動かすようにしました。

javascript

コピー
let leftPressed = false;
let rightPressed = false;

function draw() {
  // 他のコード...
  
  // スムーズなパドル移動
  if (leftPressed) {
    paddles[0].move(-10);
  } else if (rightPressed) {
    paddles[0].move(10);
  }
}

function keyPressed() {
  if (keyCode === LEFT_ARROW) {
    leftPressed = true;
  } else if (keyCode === RIGHT_ARROW) {
    rightPressed = true;
  }
}

function keyReleased() {
  if (keyCode === LEFT_ARROW) {
    leftPressed = false;
  } else if (keyCode === RIGHT_ARROW) {
    rightPressed = false;
  }
}
壁の当たり判定の修正
以前の実装:
以前のコードでは、壁との衝突時のボールの反発が正しく処理されず、
ボールが画面外に出てしまうことがありました。

javascript

コピー
class Ball {
  // 他のコード...

  hits(wall) {
    let d = dist(ball.pos.x, ball.pos.y, this.pos.x + this.w / 2, this.pos.y + this.h / 2);
    return (d < ball.r + min(this.w, this.h) / 2);
  }
}
改善後の実装:
壁との衝突判定を改善し、ボールが正しく反発するようにしました。
壁が垂直（左または右）か水平（上）かをチェックし、
それに応じて反発の方向を変更します。

javascript

コピー
class Ball {
  // 他のコード...

  bounceOffWall(wall) {
    if (wall.w > wall.h) {
      this.vel.y *= -1;
    } else {
      this.vel.x *= -1;
    }
  }

  hitsWall(wall) {
    return (
      this.pos.x + this.r > wall.pos.x &&
      this.pos.x - this.r < wall.pos.x + wall.w &&
      this.pos.y + this.r > wall.pos.y &&
      this.pos.y - this.r < wall.pos.y + wall.h
    );
  }
}
この修正により、ボールが壁に当たったときに適切に反発し、
ゲーム画面外に出なくなります。

これらの改善により、ブロック崩しのゲームとしてより適切に動作するようになりました。
他にも質問や改善したい点があれば、どうぞお知らせください！
```

```
あなたの発言
ありがとうございます。
ではブロック崩しのメインである、ブロックを配置していただけますでしょうか？
```


```
Copilot の発言
もちろんです！
では、ブロック崩しのためにブロックを配置するコードを追加しましょう。
以下のコードにブロッククラスを追加し、複数のブロックを配置するようにします。
```

<details><summary>javascript</summary>

javascript

コピー
let ball;
let paddles = [];
let walls = [];
let blocks = [];
let score = 0;
let leftPressed = false;
let rightPressed = false;

function setup() {
  createCanvas(600, 400);
  ball = new Ball();
  paddles.push(new Paddle(width / 2 - 50, height - 20, 100, 10));
  walls.push(new Wall(0, 0, 10, height)); // 左の壁
  walls.push(new Wall(width - 10, 0, 10, height)); // 右の壁
  walls.push(new Wall(0, 0, width, 10)); // 上の壁

  // ブロックの配置
  let rows = 5;
  let cols = 10;
  let blockWidth = 50;
  let blockHeight = 20;
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      blocks.push(new Block(j * blockWidth + 10, i * blockHeight + 40, blockWidth, blockHeight));
    }
  }
}

function draw() {
  background(0);

  ball.update();
  ball.show();

  for (let paddle of paddles) {
    paddle.show();
    if (ball.hitsPaddle(paddle)) {
      ball.bounceOffPaddle();
      score += 10;
    }
  }

  for (let wall of walls) {
    wall.show();
    if (ball.hitsWall(wall)) {
      ball.bounceOffWall(wall);
    }
  }

  // ブロックの表示と衝突判定
  for (let i = blocks.length - 1; i >= 0; i--) {
    blocks[i].show();
    if (ball.hitsBlock(blocks[i])) {
      ball.bounceOffBlock();
      blocks.splice(i, 1); // ブロックを削除
      score += 20;
    }
  }

  // スムーズなパドル移動
  if (leftPressed) {
    paddles[0].move(-10);
  } else if (rightPressed) {
    paddles[0].move(10);
  }

  fill(255);
  textSize(16);
  text("Score: " + score, 10, 30);

  if (ball.offScreen()) {
    textSize(32);
    text("Game Over", width / 2 - 80, height / 2);
    noLoop();
  }
}

function keyPressed() {
  if (keyCode === LEFT_ARROW) {
    leftPressed = true;
  } else if (keyCode === RIGHT_ARROW) {
    rightPressed = true;
  }
}

function keyReleased() {
  if (keyCode === LEFT_ARROW) {
    leftPressed = false;
  } else if (keyCode === RIGHT_ARROW) {
    rightPressed = false;
  }
}

class Ball {
  constructor() {
    this.pos = createVector(width / 2, height / 2);
    this.vel = createVector(3, 3);
    this.r = 12;
  }

  update() {
    this.pos.add(this.vel);
  }

  show() {
    fill(255);
    ellipse(this.pos.x, this.pos.y, this.r * 2);
  }

  bounceOffPaddle() {
    this.vel.y *= -1;
  }

  hitsPaddle(paddle) {
    return (
      this.pos.y + this.r > paddle.pos.y &&
      this.pos.x > paddle.pos.x &&
      this.pos.x < paddle.pos.x + paddle.w
    );
  }

  bounceOffWall(wall) {
    if (wall.w > wall.h) {
      this.vel.y *= -1;
    } else {
      this.vel.x *= -1;
    }
  }

  hitsWall(wall) {
    return (
      this.pos.x + this.r > wall.pos.x &&
      this.pos.x - this.r < wall.pos.x + wall.w &&
      this.pos.y + this.r > wall.pos.y &&
      this.pos.y - this.r < wall.pos.y + wall.h
    );
  }

  bounceOffBlock() {
    this.vel.y *= -1;
  }

  hitsBlock(block) {
    return (
      this.pos.x + this.r > block.pos.x &&
      this.pos.x - this.r < block.pos.x + block.w &&
      this.pos.y + this.r > block.pos.y &&
      this.pos.y - this.r < block.pos.y + block.h
    );
  }

  offScreen() {
    return (this.pos.y > height);
  }
}

class Paddle {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
  }

  show() {
    fill(255);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }

  move(step) {
    this.pos.x += step;
    this.pos.x = constrain(this.pos.x, 0, width - this.w);
  }
}

class Wall {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
  }

  show() {
    fill(255);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }
}

class Block {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
  }

  show() {
    fill(255, 0, 0);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }
}
</details>

```
新しいコードの解説
ブロックの配置:

setup関数内で、複数のブロックを配置しています。
各ブロックの幅と高さを設定し、
行と列をループしてブロックを生成しています。

ブロックの表示と衝突判定:

draw関数内で、各ブロックを表示し、ボールとの衝突判定を行います。
衝突が検知された場合、ボールの方向を反転させ、
ブロックを削除し、スコアを加算します。

Blockクラス:

ブロックの位置 (pos)、幅 (w)、高さ (h) を定義し、
ブロックを表示するメソッド (show) を持ちます。

これでブロック崩しの基本的な機能が実装されています。
さらにカスタマイズして、楽しんでくださいね！
他にも質問や改善したい点があれば、いつでもどうぞ。
```


```
あなたの発言
思った通りの動きとなっています！
ブロックを全て崩したらゲームクリア、
といったメッセージを出してゲームが終わるようにできますでしょうか？
また、エンディングがあるならオープニングもほしいのですが、
簡単なタイトル画面も追加いただけますでしょうか？
```

```
Copilot の発言
すごいですね！
ゲームクリアとオープニングを追加して、より完成度の高いブロック崩しにしましょう。

変更点:
タイトル画面を追加。

ブロックを全て崩した際のゲームクリアメッセージを追加。

以下が改良されたコードです:
```

<details><summary>javascript</summary>

javascript

コピー
let ball;
let paddles = [];
let walls = [];
let blocks = [];
let score = 0;
let leftPressed = false;
let rightPressed = false;
let gameState = 'title'; // 'title', 'playing', 'gameOver', 'gameClear'

function setup() {
  createCanvas(600, 400);
  createGameElements();
}

function createGameElements() {
  ball = new Ball();
  paddles = [new Paddle(width / 2 - 50, height - 20, 100, 10)];
  walls = [
    new Wall(0, 0, 10, height), // 左の壁
    new Wall(width - 10, 0, 10, height), // 右の壁
    new Wall(0, 0, width, 10) // 上の壁
  ];
  blocks = [];
  let rows = 5;
  let cols = 10;
  let blockWidth = 50;
  let blockHeight = 20;
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      blocks.push(new Block(j * blockWidth + 10, i * blockHeight + 40, blockWidth, blockHeight));
    }
  }
  score = 0;
  leftPressed = false;
  rightPressed = false;
}

function draw() {
  background(0);

  if (gameState === 'title') {
    drawTitleScreen();
  } else if (gameState === 'playing') {
    playGame();
  } else if (gameState === 'gameOver') {
    drawGameOverScreen();
  } else if (gameState === 'gameClear') {
    drawGameClearScreen();
  }
}

function drawTitleScreen() {
  fill(255);
  textSize(32);
  textAlign(CENTER);
  text("Breakout Game", width / 2, height / 2 - 20);
  textSize(16);
  text("Press Enter to Start", width / 2, height / 2 + 20);
}

function playGame() {
  ball.update();
  ball.show();

  for (let paddle of paddles) {
    paddle.show();
    if (ball.hitsPaddle(paddle)) {
      ball.bounceOffPaddle();
      score += 10;
    }
  }

  for (let wall of walls) {
    wall.show();
    if (ball.hitsWall(wall)) {
      ball.bounceOffWall(wall);
    }
  }

  for (let i = blocks.length - 1; i >= 0; i--) {
    blocks[i].show();
    if (ball.hitsBlock(blocks[i])) {
      ball.bounceOffBlock();
      blocks.splice(i, 1); // ブロックを削除
      score += 20;
    }
  }

  if (blocks.length === 0) {
    gameState = 'gameClear';
  }

  if (leftPressed) {
    paddles[0].move(-10);
  } else if (rightPressed) {
    paddles[0].move(10);
  }

  fill(255);
  textSize(16);
  text("Score: " + score, 10, 30);

  if (ball.offScreen()) {
    gameState = 'gameOver';
  }
}

function drawGameOverScreen() {
  fill(255);
  textSize(32);
  textAlign(CENTER);
  text("Game Over", width / 2, height / 2 - 20);
  textSize(16);
  text("Press Enter to Restart", width / 2, height / 2 + 20);
}

function drawGameClearScreen() {
  fill(255);
  textSize(32);
  textAlign(CENTER);
  text("Congratulations!", width / 2, height / 2 - 20);
  text("You cleared all the blocks!", width / 2, height / 2 + 20);
  textSize(16);
  text("Press Enter to Restart", width / 2, height / 2 + 60);
}

function keyPressed() {
  if (keyCode === LEFT_ARROW) {
    leftPressed = true;
  } else if (keyCode === RIGHT_ARROW) {
    rightPressed = true;
  } else if (keyCode === ENTER) {
    if (gameState === 'title' || gameState === 'gameOver' || gameState === 'gameClear') {
      createGameElements();
      gameState = 'playing';
    }
  }
}

function keyReleased() {
  if (keyCode === LEFT_ARROW) {
    leftPressed = false;
  } else if (keyCode === RIGHT_ARROW) {
    rightPressed = false;
  }
}

class Ball {
  constructor() {
    this.pos = createVector(width / 2, height / 2);
    this.vel = createVector(3, 3);
    this.r = 12;
  }

  update() {
    this.pos.add(this.vel);
  }

  show() {
    fill(255);
    ellipse(this.pos.x, this.pos.y, this.r * 2);
  }

  bounceOffPaddle() {
    this.vel.y *= -1;
  }

  hitsPaddle(paddle) {
    return (
      this.pos.y + this.r > paddle.pos.y &&
      this.pos.x > paddle.pos.x &&
      this.pos.x < paddle.pos.x + paddle.w
    );
  }

  bounceOffWall(wall) {
    if (wall.w > wall.h) {
      this.vel.y *= -1;
    } else {
      this.vel.x *= -1;
    }
  }

  hitsWall(wall) {
    return (
      this.pos.x + this.r > wall.pos.x &&
      this.pos.x - this.r < wall.pos.x + wall.w &&
      this.pos.y + this.r > wall.pos.y &&
      this.pos.y - this.r < wall.pos.y + wall.h
    );
  }

  bounceOffBlock() {
    this.vel.y *= -1;
  }

  hitsBlock(block) {
    return (
      this.pos.x + this.r > block.pos.x &&
      this.pos.x - this.r < block.pos.x + block.w &&
      this.pos.y + this.r > block.pos.y &&
      this.pos.y - this.r < block.pos.y + block.h
    );
  }

  offScreen() {
    return (this.pos.y > height);
  }
}

class Paddle {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
  }

  show() {
    fill(255);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }

  move(step) {
    this.pos.x += step;
    this.pos.x = constrain(this.pos.x, 0, width - this.w);
  }
}

class Wall {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
  }

  show() {
    fill(255);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }
}

class Block {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
  }

  show() {
    fill(255, 0, 0);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }
}
</details>


```
追加された機能
タイトル画面: drawTitleScreen関数でタイトル画面を描画し、ENTERキーを押すとゲームが開始します。

ゲームクリア画面: drawGameClearScreen関数で全てのブロックを崩した際のメッセージを表示し、
　　　　　　　　　ENTERキーを押すとゲームが再スタートします。

ゲームオーバー画面: drawGameOverScreen関数でボールが画面外に出た際のメッセージを表示し、
　　　　　　　　　　ENTERキーを押すとゲームが再スタートします。

これでブロック崩しゲームがさらに楽しくなるはずです！
他にも質問や改善点があれば、遠慮なくお知らせください。

Copilot へメッセージを送る
```

## 感想
- Copilotも普通に動くものが一瞬で提供される。凄い。修正も一瞬。
- p5jsとかキーリピートとか当たり判定とか、考え方は知ってないと調整の依頼が難しいかも。
- 今やvscodeに統合されて生成AIのウインドウと行ったり来たりしなくて良いものもあるということで、益々便利なんだろうと思うけど、この使い方でも十分凄い。
- ピンボールってオーダーに何故ブロック崩しが来たのかは謎。
- コード修正の度にdiff取って確認は自分で手動。ここもやってくれたら便利。
- 無駄がないか、より良い実装はないか、ということは分からない。
でも、動くものを作ってもらって、そこから勉強ができる。
- copilotログインせずに利用したのでこの会話は消えてしまっており、「スマホ操作に対応したい」とか、機能追加してない。

## 追記　公開する際の検討
- ここはChatGPTにお願いしました。
一覧ページの提案がほんとおしゃれで凄いと思いました。
- 端的には、GitHub Pagesで、複数のゲームバージョンを公開して、今回のCopilot作のゲーム進化を見てもらいたい、
という要件を伝えて、方法の提案をしてもらい、HTMLの提案もしてもらった感じです。

https://chatgpt.com/share/67b96857-63b8-8008-a470-581767ef051d

以上