1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Unity】壁との弾性衝突を実装する

Last updated at Posted at 2022-11-02

壁との弾性衝突とは

Untitled.png
入射角と反射角が同じように跳ね返り、跳ね返りの前後で速さが変わらない運動を指します。

標準の物理特性マテリアルでは挙動関係でバグが起こりやすいため、手製のものを実装しましょう。

2Dゲームの場合の実装

弾性衝突させたいオブジェクトに、Rigidbody2Dとともに下記のBouce.csをアタッチしてください。

public変数のvelocityで速度を操作しています。
AddForceなどで運動に介入しようとしても速度はvelocityで固定されます。
もし衝突以外で運動を操作する場合は、velocity変数を書き換えるか、Update関数の処理を一時的にオフにする処理を書き加えてください。

Bounce.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bounce : MonoBehaviour
{
    public Vector2 velocity;

    private void Update()
    {
        GetComponent<Rigidbody2D>().velocity = velocity;
    }

    public void OnCollisionEnter2D(Collision2D collision)
    {
        Vector2 velocityNext
            = Vector2.Reflect(velocity, collision.contacts[0].normal);
        velocity = velocityNext;  
    }
}

3Dゲームの場合の実装

弾性衝突させたいオブジェクトに、Rigidbodyとともに下記のBouce.csをアタッチしてください。

public変数のvelocityで速度を操作しています。
AddForceなどで運動に介入しようとしても速度はvelocityで固定されます。
もし衝突以外で運動を操作する場合は、velocity変数を書き換えるか、Update関数の処理を一時的にオフにする処理を書き加えてください。

Bounce.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bounce : MonoBehaviour
{
    public Vector3 velocity;

    private void Update()
    {
        GetComponent<Rigidbody>().velocity = velocity;
    }

    public void OnCollisionEnter(Collision collision)
    {
        Vector3 velocityNext
            = Vector3.Reflect(velocity, collision.contacts[0].normal);
        velocity = velocityNext;  
    }
}

仕組み

仕組みは単純です。
Vector2ないしVector3クラスにReflect関数があります
Vector3.Reflect(速度ベクトル, 法線ベクトル)

法線ベクトルとは、ざっくり言うと下図のイメージです。
ちゃんとした説明でいうと、「衝突面に垂直なベクトル」です。
Untitled.png

速度ベクトルはvelocityで与えられます。

衝突面の法線ベクトルは、OnCollisionEnterの引数に与えられるCollisionの中のContactに含まれています。
具体的には、collision.contacts[0].normalです。
これをReflect()に与えることで、弾性衝突後の速度ベクトルを与えてくれます。

なぜvelocity変数を作るのか

当然の疑問として、なぜわざわざvelocity変数で速度を管理して速度の管理を不自由にするのか、なぜReflect()GetComponent()<Rigidbody>().velocityを直接与えないのか、と思われると思います。
その理由としては、OnCollisionEnter()が呼ばれる時には既にRigidbody.velocityが既に衝突後の数値になってしまうからなんですよね。
デフォルトだと非弾性衝突(跳ね返らず、壁にひっつくような衝突)をしますが、その値が既にRigidbody.velocityに代入されてしまい、衝突前の数値をReflect()に与えることができなくなってしまいます。
そういった事情で、衝突前の速度ベクトルを把握するために、velocityで管理しています。

もしUpdate関数でRigidbody.velocityを上書きしなくとも衝突前のRigidbody.velocityを掴める実装を思いつけたら、そっちのほうがいいでしょうね、、

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?