受ける板が動いているときに球がぶつかる状態になると、板をすり抜けてしまうことが起こります。トンネル効果というみたいですね。これを回避するコードも書けるようですが、いまのところよくわかりませんので、すり抜け現象をしばらく楽しみたいと思います。
今回のコードは円などの生成をクラスを使ってみました。
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;
}