ブロックの円を増やしたことと、板とぶつかる位置によって跳ね返り方を変えるなどの変化を付けてみました。

const NUM_BLOCKS = 18;
const BLOCK_ROW = 6;
const BLOCK_RADIUS = 15;
const MOVING_RADIUS = 8;
const RECT_WIDTH = 100;
const RECT_HEIGHT = 20;

let blocks = [];
let movingBall;
let bounceRect;
let score = 0;

class Ball {
  constructor(x, y, r, col) {
    this.pos = createVector(x, y);
    this.r = r;
    this.col = col;
    this.visible = true;
    this.velocity = createVector(-3, 3);
  }

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

  display() {
    fill(this.col);
    circle(this.pos.x, this.pos.y, this.r * 2);
  }
}

class Rect {
  constructor(x, y, w, h) {
    this.pos = createVector(x, y);
    this.w = w;
    this.h = h;
    this.col = color(0, 255, 255);
  }

  display() {
    fill(this.col);
    rect(this.pos.x, this.pos.y, this.w, this.h);
  }
}

function setup() {
  createCanvas(400, 400);
  noStroke();
  textSize(24);
  textAlign(LEFT, TOP);
  
//Ballクラスのインスタンスを生成して配列に
  for (let i = 0; i < NUM_BLOCKS; i++) {
    const x = (width / (BLOCK_ROW + 1)) * ((i % BLOCK_ROW) + 1);
    const y = Math.floor(i / BLOCK_ROW) * 50 + 80;
    blocks.push(new Ball(x, y, BLOCK_RADIUS, color(100, 200, 250)));
  }
  
//ぶつける球のインスタンス生成
  movingBall = new Ball(width / 2, height / 2, MOVING_RADIUS, color(250, 100, 100));

//受ける板のインスタンス生成
  bounceRect = new Rect(width / 2, height - RECT_HEIGHT - 20, RECT_WIDTH, RECT_HEIGHT);
}

function draw() {
  background(220);

  //的の円を描画
  for (const block of blocks) {
    if (block.visible) {
      block.display();
    }
  }

  //受ける板の描画
  bounceRect.display();
  //板をマウスに追随させる(マウスの位置が板の真ん中にくるように)
  bounceRect.pos.x = constrain(mouseX, bounceRect.w / 2,
     width - (bounceRect.w / 2)) - bounceRect.w / 2;

  //ぶつける球の描画
  movingBall.display();
  
  //ぶつける球の移動
  movingBall.update();

  // 壁との反射
  if (movingBall.pos.x < movingBall.r || movingBall.pos.x > width - movingBall.r) {
    movingBall.velocity.x *= -1;
  }
  if (movingBall.pos.y < movingBall.r) {
    movingBall.velocity.y *= -1;
  }

  // bounceRect との当たり判定
  if (
    movingBall.pos.y + movingBall.r >= bounceRect.pos.y &&
    movingBall.pos.x > bounceRect.pos.x &&
    movingBall.pos.x < bounceRect.pos.x + bounceRect.w &&
    movingBall.pos.y < bounceRect.pos.y + bounceRect.h
  ) {
    movingBall.velocity.x = Math.sign(movingBall.velocity.x)
       * abs(((bounceRect.pos.x + bounceRect.w / 2) - movingBall.pos.x) / 10);
    movingBall.velocity.y = random(-3, -5);
  }

  // 下に落ちたらリセット
  if (movingBall.pos.y > height + movingBall.r) {
    movingBall.pos = createVector(width / 2, height / 2);
    movingBall.velocity = createVector(-2, 2);
    score = 0;
    for (const block of blocks) block.visible = true;
  }

  // ブロックとの当たり判定
  for (const block of blocks) {
    if (block.visible && checkCollisionBlock(block)) {
      block.visible = false;
      reflectBall(block);
      score += 10;
    }
  }

  // スコア表示
  fill(0);
  text("Score: " + score, 10, 10);
}

//ぶつける球と静止円との衝突判定
function checkCollisionBlock(target) {
  const distance = p5.Vector.dist(movingBall.pos, target.pos);
  return distance < movingBall.r + target.r;
}

//反射ベクトル計算
function reflectBall(target) {
  const normalV = p5.Vector.sub(movingBall.pos, target.pos).normalize();
  const dotM = movingBall.velocity.dot(normalV);
  const reflecV = p5.Vector.sub(
    movingBall.velocity,
    p5.Vector.mult(normalV, 2 * dotM)
  );
  movingBall.velocity = reflecV;
}
投稿者

manager

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


日本語が含まれない投稿は受付られません。(スパム対策)