【Unity】オブジェクトが画面外かどうかを判定する方法(まとめ)

2018.08.25 自習室 0

ゲームを作っていると「キャラクターやオブジェクトが画面外か画面内か」で処理を分けたいことがありますが、Unityでその判定をする方法がいくつかあって分かりにくかったので、調べたことを記事にしてまとめておきます。

環境

  • Unity 2018.1.0f3

使用アセット

判定方法

Renderer.isVisibleを使う方法

  • カメラに表示されているかをtrue, falseで返してくれる
  • カメラが複数ある場合、どのカメラにも写っていない場合のみfalseになる
  • カメラにはシーンビュー用のカメラも含まれるので注意(ゲームビューに写っていなくてもシーンビューに写っていればtrueになる)
  • オブジェクトの後ろに隠れていてカメラに写っていなくても、カメラの描画範囲内にあればtrueが返ってくる
  • 「画面外で生成される場合はNG」という情報をたまに見かけましたが、テストした限りでは画面外で生成してもちゃんと動いてました
Renderer.isVisibleの参考リンク
公式スクリプトリファレンス(日本語版最新)

OnBecameVisible、OnBecameInVisibleを使う方法

  • OnBecameVisibleはカメラに表示されるようになった時、OnBecameInVisibleはカメラに表示されなくなった時に一度だけ呼ばれる
  • RendererがアタッチされているオブジェクトにスクリプトをつけておけばOK(GetComponentで参照を取得しなくてもいい)
  • カメラが複数ある場合、どのカメラにも映っていない場合のみfalseになる
  • カメラにはシーンビュー用のカメラも含まれるので注意(ゲームビューに映っていなくてもシーンビューに映っていればtrueになる)
  • オブジェクトの後ろに隠れていてカメラに写っていなくても、カメラの描画範囲内にあればtrueが返ってくる
OnBecameVisible、OnBecameInVisibleの参考リンク
公式スクリプトリファレンス(日本語版最新)
【Unity】オブジェクトがカメラに写っているかと注意点 2017.02.13
カメラに写っている間のみ処理を行う 2013.10.07

OnWillRenderObjectを使う方法

  • カメラの表示対象になっている場合、各カメラ毎に呼ばれる
  • Camera.currentで映っているカメラが取得できる
  • シーンビュー用のカメラも対象になるが、カメラ毎に処理を切り替え可能なのでゲームビューのみを対象にすることもできる
  • RendererがアタッチされているオブジェクトにスクリプトをつけておけばOK(GetComponentで参照を取得しなくてもいい)
OnWillRenderObjectの参考リンク
公式スクリプトリファレンス(日本語版最新)
特定のカメラに映ってるかの判定【Unity】 2014.12.29
カメラに写っている間のみ処理を行う 2013.10.07

Camera.ViewportPointToRayを使う方法

  • カメラの四隅にRayを飛ばすことができる(四隅以外にも飛ばせます)
  • Rayを飛ばす位置の指定はビューポート座標系(左下は(0, 0)、右上は(1, 1))
  • Unityの座標系について、詳しくはこちらの記事(UnityのCameraが使う3つの座標系)を参照してください
  • Rayが当たったポイントの座標から画面外かどうかを判定することができる
  • Rayが何かに当たる前提なので、何もない可能性がある場合は使えない
Camera.ViewportPointToRayの参考リンク
公式スクリプトリファレンス(日本語版最新)
公式マニュアル カメラからのRay

Camera.ViewportToWorldPointを使う方法

  • カメラのビューポート空間の座標をワールド空間の座標に変換してくれる
  • Unityの座標系について、詳しくはこちらの記事(UnityのCameraが使う3つの座標系)を参照してください
  • 一つ前のCamera.ViewportPointToRayと似ているが、こちらは「カメラと水平な面の座標」しか取れない(後で画像で説明してます)
  • 引数として渡すVector3.zの値でカメラと面の間の距離を指定できます
  • 画面外判定で使えるのは2Dの場合のみだと思います。なので例も2D表示にしてます

参考:ViewportToWorldPointが3Dだと使いにくい理由

前述した通り「カメラと水平な面の座標」しか取れないのが理由なのですが、文章だと分かりにくいので画像を貼っておきます。

画面外判定するのに知りたいのは「床面がどこまでカメラに映っているか」という情報なわけですが、ViewportToWorldPointを使用した場合に取得できるのは、上の画像で黄色い球が表示されているポイントになります。

ゲームのステージとは関係なく、「カメラから一定距離離れた地点でカメラに映る範囲」が取得されてしまうので、「カメラとステージが水平で、ステージが真っ平らな場合」でないと画面外判定に使うのは難しいです。

2Dの場合は「カメラとステージが水平で、ステージが真っ平らな場合」という条件に合っているので問題なく使えます。

Camera.ViewportToWorldPointの参考リンク
公式スクリプトリファレンス(日本語版最新)
2Dと3Dの座標変換【Unity】 2015.06.29

Camera.WorldToViewportPointを使う方法

  • ワールド空間の座標をカメラのビューポート空間の座標に変換してくれる
  • Unityの座標系について、詳しくはこちらの記事(UnityのCameraが使う3つの座標系)を参照してください
  • ターゲットとなるオブジェクトの位置をカメラのビューポート座標に変換し、x座標・y座標が(0,0)から(1,1)の間にあれば画面内にあると判定できる
Camera.WorldToViewportPointの参考リンク
公式スクリプトリファレンス(日本語版最新)
Rect.Containsの公式スクリプトリファレンス(日本語版最新)
Unity】画面外のターゲットを追跡するカーソル 2016.04.26

Colliderを使う方法

  • 画面の周囲を判定用のColliderで囲んでおいて、OnTriggerEnterとかで判定する方法
  • 画面全体を覆うColliderを作っておいて、OntriggerExitで判定する方法もあります(Unity公式チュートリアルの2Dシューティングはこの方法で弾を削除してます)
  • 実装方法は関連リンクにUnity公式チュートリアルの2Dシューティングの該当箇所へのリンクを貼ってますので、そちらをご覧ください
  • スマホアプリだと端末によって画面に映る範囲が変わってしまうので、他の方法の方が使い勝手がいいと思います
Colliderの参考リンク
公式チュートリアル 2Dシューティング 当たり判定とアニメーションイベントとレイヤー

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です