【Unity】当たり判定はradiusを取るだけだと正しくないことがある

3連休最終日ですね、過去に例を見ないほどの超大型台風が関東に来るって言うので色々対策しまくっていたのですが、杞憂に終わってホッとしています子猫2000です。長期停電とかなったらすることなくて死んでしまうものね、しょうがないね。

引き続きUnityで2Dゲーム作りしてみているのですが、今日は当たり判定で詰まりました。円形の当たり判定(Circle Collider 2D)を使用しているのですが、Script上でキャラクターと壁の当たり判定を行いたかったんです。それでキャラクターの左右の座標を計算して出そうと思い、右側なら「現在座標 + 半径 + 0.1」みたいな計算式で行けるかなーと思ってScript書いたのですが、思った通り判定してくれませんでした。右の壁にピッタリくっついているのに、まだ衝突していないと判定されているようで、何も起こりませんでした。

そんなわけで備考録です。

実際の半径は対象オブジェクトに合わせてスケールする

先に結論から言うと、「現在座標 + 半径 × スケール値 + 0.1」みたくすると思った通りの判定結果となってくれました。違いは半径にスケール値を掛け算するところです。

CircleCollider2Dのドキュメントはこちら。

上記ドキュメントでは変数「radius」の説明には特に記載がないのですが、実際に動かしてみると中心座標から壁までの距離が、設定しているRadiusの値より大きいことで気づきました。というわけで修正後のソースコードが下記となり、無事に解決しました。

// 当たり判定インスタンス取得
CircleCollider2D cc2D = this.targetGameObject.GetComponent<CircleCollider2D>();

// ※当たり判定の半径は、対象オブジェクトのスケールに応じて変化することに注意
// 実際の半径
float realRadius = cc2D.radius * this.targetGameObject.transform.localScale.x;
// 右の衝突判定用座標(X座標:現在座標 + 当たり判定の半径 * スケール + 0.1)
Vector3 worldCoordinateRight = new Vector3(cc2D.transform.position.x + realRadius + 0.1f, cc2D.transform.position.y, 0.0f);
// 左の衝突判定用座標(X座標:現在座標 - 当たり判定の半径 * スケール - 0.1)
Vector3 worldCoordinateLeft = new Vector3(cc2D.transform.position.x - realRadius - 0.1f, cc2D.transform.position.y, 0.0f);

変数「targetGameObject」はクラス変数として以下のように宣言して、初期化処理でインスタンスを代入しています。

// 対象のGameObject
private GameObject targetGameObject;
public void initialize(GameObject targetGameObject, float movementSpeedModifier = 1.0f)
{
    // 対象のGameObjectへ代入
    this.targetGameObject = targetGameObject;
    (※他関係ない箇所は省略)
}

以上です。ゲームオブジェクトをスケールしている場合、「Radius」を取得するだけでなく、スケール値を掛け算することを忘れずに。