![見出し画像](https://assets.st-note.com/production/uploads/images/106779358/rectangle_large_type_2_ad8b79364063fa8689529fbcad09e3f0.png?width=1200)
【Unity】Physics2D.Raycastを使用した壁との当たり判定
自機に向かってくる敵を実装していたのですが壁との当たり判定で苦労しました。
今まで作っていた縦スクロールSTGなどは壁の位置が固定もしくは変化するにしても座標が決まっていたので、例えば if(x<0) x=0; みたいにしておけば壁との当たり判定は出来たのですが、今作っている全方位スクロールSTGだと壁の座標が常に変化しているので、この方法は使えないんですよね。
こういう場合の実装方法を調べてみると「壁に当たった時は当たった方向と逆向きに少し戻す」という実装方法が良く解説されていたので実装してみると・・・
キャラと壁との当たり判定、壁に当たったら停止とすると当たりっぱなしで動かなくなるので、当たったらちょっと戻る実装にしたんだけど、そうすると戻った時に後ろ側に壁があると駄目なのよね。なので4方向に当たり判定付けて判別すれば回避出来たんだけど当たり判定1つで上手く出来る方法あるのかなぁ pic.twitter.com/VUaseUyGOC
— kt. (@xxxx_kt_xxxx) March 5, 2023
壁に当たった時に少し戻す時に戻した側に壁があるとすり抜けてしまうんですよね。
当たり判定を小さくしたり位置を変えたり戻す量を工夫してみたりしたのですが、戻ると言う動作があると上手く作る事が出来ませんでした(上手く出来る方法はあると思うのですが私には作れなった)
そしてなにより壁に当たってちょっと戻る動きがカッコ悪い(笑)
戻る動きを使わないようにすれば良いのではないかと思って調べてみるとUnityにはRaycastと言う「透明な光線を打ち光線に当たったオブジェクトの情報を取得する機能」がある事を知りRaycastを使ってやれば上手く出来るのではないかと思って実装してみると上手く出来ました。
壁すり抜け問題、壁に当たるとちょっと戻す方法だと戻った方向に壁があるとすり抜けてしまうのでRaycastでRayを飛ばして当たったらその場で停止&角度のみ変更→Rayが当たらなくなったら移動開始にしたら上手く出来た。そして法線ベクトルを自分で計算しなくても良い事に今更気付いた#unity #gamedev pic.twitter.com/ddmNvJKB1X
— kt. (@xxxx_kt_xxxx) May 28, 2023
実装方法としてはこんな感じ
Ray2D ray = new Ray2D(transform.position, -transform.up); // Rayを生成、-transform.upは進行方向
RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, 1f);//Raycastを生成
Debug.DrawRay(ray.origin, ray.direction * 1f, Color.green, 0.015f); // 長さ1f、緑色で1フレーム可視化
if (hit.collider)
{
if (hit.collider.gameObject.layer == 12 || hit.collider.gameObject.layer == 7)//12は"kabe" 7は"teki"
{
ds = 0;//移動速度を0にする
}
Debug.Log(hit.collider.gameObject.layer);//Rayが当たった物をログ表示
Debug.DrawRay(hit.point, hit.normal * 2f, Color.green, 0.015f); // 法線ベクトル表示、長さ2f、緑色で1フレーム可視化
}
当初1本のRaycastで判定を行っていたのですが半分くらい壁に埋まってしまう時があってBoxcast(箱型のRayを飛ばす)やSphereCast(丸型のRayを飛ばす)を使ってみたのですが中心に壁が当たった時の動きが不自然だったのでオブジェクトの左右から2本のRayを飛ばして判定する方法が一番自然に見える感じに出来ました。
当たった物との判定はPhysics2D.RaycastのlayerMaskでも出来るのですがcollider側でも判別出来てhit.collider.gameObject.layerに返ってくる数字で当たった物を区別出来ます。
![](https://assets.st-note.com/img/1685325923120-psHmAFvTbG.png)
layerMaskを使って判別する場合はビット演算で記述するようです。
tekiとの接触なら1 << 7
kabeとの接触なら1 << 12
他に&や|や~演算子も使えます。(C#の記述ではなくビット演算子記述なので&&や||とは記述しない)
例えばtekiもしくはkabeとの当たり判定のみ行いたい場合は
hit = Physics2D.Raycast(ray.origin, ray.direction, 0.8f, 1 << 12 | 1 << 7);
みたいに記述します。
余談ですが
hit.pointで当たった位置
hit.normalで当たった位置の法線ベクトル
hit.distanceで当たった距離
なども取得出来るので色々と使えそうです。