Skip to main content

ボール跳ね返す角度をコントロールする

目的

今の作りだと、ボールがパドルを当たると、入射角を反転し、外向角になるだけで、プレーヤーがボール行かせたい方位を変えることができない。ある程度、ボールを行き先をコントロールできるように、パドルの「当たる部分」によって、跳ね返す向きを調整する処理を入れましょう。

image.png

これで、ボールがパドルの左側に当たると、ボールが左に行く。真ん中を当たると、真上に返す。右側を当たると、右に行くようにする。

解決のアイディア

ボールとパドルの相対位置がポイント。ボールが衝突したら、パドルの位置とボールの位置を使い、その向きに返せば良いでしょう:

image.png

スクリプト

ボールを跳ね返す責任を持つ「BallRebound」を作成しましょう。衝突に時(OnCollisionEnter2D)ボールの速度の向きを変えれば良いでしょう。

// ボールの跳ね返す角度を制御する
public class BallRebound : MonoBehaviour
{
    // 衝突のとき
    private void OnCollisionEnter2D(Collision2D other)
    {
        // "other" がボールでしょう
        // なので、RigidBodyを取得し、速度を変えましょう
        Rigidbody2D rb = other.gameObject.GetComponent<Rigidbody2D>();
        
        // 速度ベクトルの長さを保持するので、求めましょう
        float speed = rb.linearVelocity.magnitude;
        
        // 新しい向きは、ボールの位置とパドルの位置の差分で求める
        Vector2 direction = other.transform.position - transform.position;
        
        // 長さが1(単位ベクトル)にする
        direction.Normalize();
        
        // 新しい速度は、前の速度(量)× 新しい向きにする
        rb.linearVelocity = direction * speed;
    }
}

このスクリプトを「player」にアタッチし、試してみると、ボールをうまくコントロールできるようになったが、パドルが壁とぶつけると:

image.png

image.png

のエラーが発生してしまう。

エラーを解決:タグを使用

今の処理だと「衝突したら」だけなので、何と衝突するのかを確認していない。ボールの場合は、ボールのリジッドボディを取得し、速度を問題なく変えられるが、壁と衝突するとバグってしまう。

なぜなら、壁がリジッドボディがなく、GetComponent<Rigidbody2D>() を呼び出すが失敗してしまうから。

なので、衝突したときに、何と衝突したのかを「タグ」で確認しましょう。まず、スクリプトを修正し、「Ball」タグがなければ、何も処理しない部分を追加しましょう。

// ボールの跳ね返す角度を制御する
public class BallRebound : MonoBehaviour
{
    // 衝突のとき
    private void OnCollisionEnter2D(Collision2D other)
    {
        // "other"が "Ball"タグがないか?
        if (!other.gameObject.CompareTag("Ball"))
        {
            return; // メソッドがここで終わり
        }
        
        // "other" がボールでしょう
        // なので、RigidBodyを取得し、速度を変えましょう
        Rigidbody2D rb = other.gameObject.GetComponent<Rigidbody2D>();
        
        // 速度ベクトルの長さを保持するので、求めましょう
        float speed = rb.linearVelocity.magnitude;
        
        // 新しい向きは、ボールの位置とパドルの位置の差分で求める
        Vector2 direction = other.transform.position - transform.position;
        
        // 長さが1(単位ベクトル)にする
        direction.Normalize();
        
        // 新しい速度は、前の速度(量)× 新しい向きにする
        rb.linearVelocity = direction * speed;
    }
}

そして、ボールのプレハブを編集し、「Ball」タグをつけましょう(小文字・大文字の注意を!):

image.png

これで問題解決!