受ける板が動いているときに球がぶつかる状態になると、板をすり抜けてしまうことが起こります。トンネル効果というみたいですね。これを回避するコードも書けるようですが、いまのところよくわかりませんので、すり抜け現象をしばらく楽しみたいと思います。
今回のコードは円などの生成をクラスを使ってみました。
const NUM_BLOCKS = 8; const BLOCK_ROW = 4; const BLOCK_RADIUS = 20; const MOVING_RADIUS = 10; 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(-2, 2); } 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 = i < BLOCK_ROW ? 80 : 160; 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, 0, width - bounceRect.w); //ぶつける球の描画 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.y *= -1; // 軽くランダム要素を入れて反射角を調整 movingBall.velocity.x += random(-0.5, 0.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; }