[JavaScript] ベクトル演算の基礎をブロック崩しゲームで学ぼう

1. ベクトル演算の基礎

ベクトルとは?

  • ベクトル は、大きさ(長さ)方向 を持つ量です。ベクトルは、通常 位置速度 などを表すために使われます。

  • ベクトルは 2次元や 3次元の座標系で表すことができます。例えば、2次元の座標系では次のように書きます:

    // 2次元ベクトル (x, y)
    let vector = { x: 3, y: 4 };  // このベクトルは、x方向に3、y方向に4だけ進む
    

    ここで、xy がベクトルの成分です。ベクトルの大きさを求めるには、この成分を使います。

ベクトルの基本演算

  • 加算: 2つのベクトルを加えると、それぞれの方向の成分を足すことになります。例えば、次のように2つのベクトルを加算できます。

    let vector1 = { x: 3, y: 4 };
    let vector2 = { x: 1, y: 2 };
    
    let result = { x: vector1.x + vector2.x, y: vector1.y + vector2.y };
    console.log(result); // { x: 4, y: 6 }
    

    ここで、vector1vector2 の各成分を足し合わせています。結果として得られるベクトルは、元の2つのベクトルが「合成」されたものです。

  • スカラー倍: ベクトルにスカラー(数値)を掛けることで、そのベクトルの大きさを変えたり、方向を変更したりできます。例えば、次のようにスカラー倍を行います。

    let vector = { x: 3, y: 4 };
    let scalar = 2;
    
    let result = { x: vector.x * scalar, y: vector.y * scalar };
    console.log(result); // { x: 6, y: 8 }
    

    ここでは、ベクトルを2倍して、進行方向を 2倍の速さ で移動するようにしています。

  • 内積(ドット積): 2つのベクトルの間にある角度を求めるために使用します。内積は次の式で計算できます:

    let vector1 = { x: 3, y: 4 };
    let vector2 = { x: 1, y: 2 };
    
    let dotProduct = vector1.x * vector2.x + vector1.y * vector2.y;
    console.log(dotProduct); // 3*1 + 4*2 = 11
    

    内積の結果は、2つのベクトル間の角度や、2つのベクトルがどれだけ似ているかを示す重要な情報です。内積が大きいほど、ベクトルは似ている(方向が近い)ことを示します。

ベクトルの長さ(大きさ)を計算する方法

ベクトルの**大きさ(長さ)**は、次のように計算できます。例えば、2次元ベクトル (x, y) の大きさは以下の式で求めます:

let vector = { x: 3, y: 4 };

let magnitude = Math.sqrt(vector.x * vector.x + vector.y * vector.y);
console.log(magnitude); // 5
  • これは、ピタゴラスの定理に基づいています。ベクトル (x, y) の長さ(大きさ)は、xy のそれぞれの成分の二乗の和の平方根です。

ベクトルの長さは、どれくらい遠くに進んだか、または どれくらいの速さで移動しているか を表します。


2. ベクトル演算を使ったブロック崩しゲームの実装

次に、実際に ブロック崩しゲーム にベクトル演算をどのように使うかを見ていきます。

ボールの移動と速度

ボールの移動は、ベクトルを使って表現できます。ボールの速度ベクトルは (speedX, speedY) で表現され、時間とともにその位置が更新されます。

let ball = { x: 100, y: 100, speedX: 5, speedY: 5 };

// ボールの移動
ball.x += ball.speedX;
ball.y += ball.speedY;

ボールと壁の衝突

壁に衝突したときは、速度ベクトルを反転させることで、ボールを跳ね返すことができます。反射を計算するために、速度のX成分やY成分を反転させます

if (ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
  ball.speedX *= -1; // X方向の速度を反転
}

if (ball.y - ball.radius < 0) {
  ball.speedY *= -1; // Y方向の速度を反転
}

パドルとの衝突と反射角度の変更

ボールがパドルの中央に当たったとき、反射角度を変更するために、ボールとパドルの位置を基に角度を計算します。この方法で、ボールの跳ね返り角度を自然に調整できます。

const relativeIntersect = (ball.x - (paddle.x + paddle.width / 2)) / (paddle.width / 2);
const bounceAngle = relativeIntersect * (Math.PI / 3); // ±60度の範囲で反射
const speed = Math.sqrt(ball.speedX * ball.speedX + ball.speedY * ball.speedY);

ball.speedX = speed * Math.sin(bounceAngle);
ball.speedY = -Math.abs(speed * Math.cos(bounceAngle));

ここでは、ボールがパドルの中央からどれくらいズレているかを計算し、そのズレに応じてボールの進行方向(角度)を変更します。


まとめ

  • ベクトル演算を使うと、ゲームの物理的な挙動をより自然に表現することができます。特に、ボールの移動や反射において重要です。
  • 加算スカラー倍内積を活用することで、ボールの速度や反射角度を計算できます。
  • Math.sqrt, Math.cos, Math.sin, Math.atan2 を使うことで、物理的に現実的な動きや反射をシミュレートできます。

3. パドルとの衝突と角度変更

パドルに当たったときの反射角度の計算

パドルにボールが当たったとき、反射の角度は パドルの中央と端で異なります。パドルの中央に当たると、ボールは真上に跳ねるのに対し、端に当たると、ボールが斜めに跳ねます。これにより、ゲームにおいてボールの動きがよりリアルになり、難易度の調整も可能になります。

  1. パドルの中央に当たった場合:

    • ボールは垂直に跳ね返ります(Y方向に反射)。
  2. パドルの端に当たった場合:

    • ボールは斜めに反射します。これは、パドルの中心からどれくらいズレているかによって反射角度が変わるためです。

反射角度を計算する方法

反射角度を決めるためには、ボールがパドルの中央からどれだけずれているかを計算します。そのズレをもとに、反射角度を決めることができます。

  1. ズレの計算:

    • ボールがパドルの中央からどれだけずれているかを計算します。パドルの幅を基に、ボールが当たる位置が中央からどれくらいずれているかを求めます。
    const relativeIntersect = (ballX - (paddle.x + paddle.width / 2)) / (paddle.width / 2);
    
    • relativeIntersect は、ボールがパドルの中央からどれくらいズレているかを示します。値が -1 の場合は、ボールがパドルの左端に当たったことを意味し、値が 1 の場合は、ボールが右端に当たったことを意味します。
  2. 反射角度の計算:

    • relativeIntersect を使って、反射の角度(bounceAngle)を計算します。反射角度は、ボールの進行方向に合わせて変わります。
    const bounceAngle = relativeIntersect * (Math.PI / 3);  // ±60度の範囲で反射
    
    • Math.PI / 3 は、±60度の範囲でボールが跳ね返るように設定しています。これによって、ボールがパドルの端に当たると、より鋭角に跳ね返ります。

ボールの速度を更新

反射角度が決まったら、ボールの速度(speedXspeedY)を更新します。速度ベクトルは、反射角度に基づいて計算されます。以下のステップで 新しい速度 を計算します:

  1. 現在の速度の大きさspeed)を計算します。これには、X成分とY成分の平方を足して、その平方根を取ります。

    const speed = Math.sqrt(gameConfig.ball.speedX * gameConfig.ball.speedX + gameConfig.ball.speedY * gameConfig.ball.speedY);
    
  2. 反射角度に基づいて、速度ベクトルを再計算します。Math.sinMath.cos を使って、反射後の X成分とY成分 を計算します。

    gameConfig.ball.speedX = speed * Math.sin(bounceAngle);  // 新しいX方向の速度
    gameConfig.ball.speedY = -Math.abs(speed * Math.cos(bounceAngle));  // 新しいY方向の速度
    
    • Math.sin(bounceAngle)Math.cos(bounceAngle) を使って、新しい方向に合わせた速度を設定します。
    • Math.abs を使って、ボールが上方向に跳ねるように (Y軸の速度を常に負にする) しています。

コード全体の流れ

  1. パドルとの衝突判定を行います。
  2. 衝突位置のズレを計算し、そのズレに基づいて反射角度を計算します。
  3. 反射角度を使って、新しい速度ベクトルを計算します。
  4. ボールの進行方向速度を反映させて、ボールの移動を更新します。

まとめ

  • パドルに当たったときの反射角度は、ボールがパドルの中央からどれだけずれているかによって決まります。
  • ズレに基づいて反射角度を計算し、その角度に基づいて新しい速度ベクトルを計算します。
  • 反射角度の計算と、ベクトルの大きさを保ちながら方向を変更することで、ボールが自然に反射するようになります。