質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

14191閲覧

Unity : 広範囲にRayを飛ばしたい(BoxCastを検討しています)

japomondo

総合スコア23

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

1グッド

0クリップ

投稿2018/01/24 17:08

編集2018/01/25 15:35

実現したいこと

Unityにおけるゲーム開発で、広範囲にRayを飛ばしたい

詳細

Unityで3Dのゲームを開発しており、ユーザーが操作するプレイヤーをNPCが探し回る、という内容を考えています。

通常時は決まったルートを巡回しているNPCが、自身の子オブジェクトから発するRayがプレイヤーのコライダにヒットした場合、追跡モードに切り替わる、という仕様を考えています。

当初はRayCastを複数発することにより実現できました。しかしながら、RayCastは処理が非常に重いと判断したため、別の方法を模索し始めました。そこでBoxCastの存在を知り色々と試してみたのですが、思うように実現することができなかったためご相談させていただいております。

実現したい内容は以下のイメージです(上空からの視点)。カメラコンポーネントが付与されているオブジェクトがプレイヤー、オレンジ色のオブジェクトがNPCで、NPCから長方形のBoxCastを発したいと考えています。

なお白い線は、NPCの子オブジェクトにアタッチした下記のコードによるものです。

イメージ説明

C#

1public class Boxcast : MonoBehaviour 2{ 3 Transform myTransform; 4 RaycastHit hit; 5 6 public float rayLength = 15/2f; 7 public Vector3 rayRange = new Vector3(8,0.1f,15); 8 9void OnDrawGizmos() 10 { 11 Gizmos.DrawWireCube (myTransform.position + myTransform.forward * rayLength, rayRange); 12 } 13}

長方形以内にプレイヤーがいた場合コライダがヒットし、NPCを追跡モードに切り替える、という仕様を想定しています。同クラスに下記のコードを書いているのですが、1枚目のイメージどおりに実装できておりません。

C#

1 void FixedUpdate () 2 { 3 Ray(); 4 } 5 6 void Ray () 7 { 8 RaycastHit hit; 9 10 if (Physics.BoxCast (myTransform.position + myTransform.forward * rayLength, rayRange, myTransform.forward, out hit, myTransform.rotation, 0)) 11 { 12 if (hit.collider.tag == "Player") 13 { 14   // 追跡を開始するコード 15 } 16 } 17 }

以上の内容にて、解決策がお分かりの方がいらっしゃいましたら、ご助言いただけますと大変助かります。なお、BoxCastに固執しているわけではありませんので、他の実現方法をご存知という場合でもコメントいただけますと幸いです。

説明が長くなり恐縮です。

参考にした情報

https://docs.unity3d.com/jp/540/ScriptReference/Physics.BoxCast.html
http://tsubakit1.hateblo.jp/entry/2016/02/25/025922

追記(コードのみ記載)

C#

1using UnityEngine; 2using System.Collections; 3using UniRx; 4using UniRx.Triggers; 5 6public class Boxcast : MonoBehaviour 7{ 8 Transform myTransform; 9 10 RaycastHit hit; 11 12 // Rayボックスの各軸の半分のサイズ 13 public Vector3 rayRange = new Vector3(5, 0.05f, 0.05f); 14 15 // Rayの最大距離 16 public float rayLength = 15; 17 18 GameObject player; 19 20 void Start () 21 { 22 myTransform = transform; 23 24 player = GameObject.FindWithTag("Player"); 25 26   // コライダがヒットした場合、追跡モードに切り替え 27 this.UpdateAsObservable() 28 .Where(_ => Physics.BoxCast (myTransform.position, rayRange, myTransform.forward, out hit, myTransform.rotation, rayLength) && hit.collider.tag == "Player") 29 .Subscribe(_ => Ray()); 30 } 31 32 void Ray () 33 { 34 // 追跡を開始するコードを記載 35 } 36} 37
Yuki_Unity👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

追跡者の前方に位置する直方体を距離0で射出することで、結果的に図中の白い長方形の範囲をスキャンしようという意図かと思いますが、ご提示いただいた【Unity】SphereCastやBoxcastで、球や箱のあたり判定が通過できるか判断する - テラシュールブログによると

BoxCastとSphereCastの死角

BoxcastSphereCastを利用する上での注意点として、開始地点を含まないといった物があります。

20160225023229.jpg

例えば下のように接触対象がめり込んでいる場合、判定の範囲外になるのでスルーして上まで線が延びてしまっています。

20160225094450.jpg

これを回避するために各Castの発信位置を下げるのはあまり面白くないので、判定の内側はCheckSphereCheckBox、もしくはOverlapBoxOverlapSphereのようなAPIで埋めてしまうのが良いかなと思います

とのことですので、おそらくご提示の図の白い長方形内は判定範囲外になってしまい、ヒットを検出できないのではないかと思います。

サイトで言及されているCheckBoxまたはOverlapBoxによる方法に変更してみてはいかがでしょうか?

※CheckBoxやOverlapBoxとレイキャスティングを複合させるのも面白そうです。たとえば...

  • CheckBoxでプレイヤーのレイヤーを対象に判定を行い、白長方形内にプレイヤーが存在するか判定する。
  • プレイヤーの存在が検出されたら、「追跡者forward」ベクトルと「プレイヤーposition - 追跡者position」ベクトルの成す角度を調べ、これが一定以下なら「プレイヤーが追跡者の視界内にいる」と判定する。
  • プレイヤーが視界内にいれば、次にプレイヤー周辺を狙って数本のレイを射出しプレイヤーとヒットするか判定する。このとき、対象レイヤーは建物など他オブジェクトのレイヤーも含めるようにして、プレイヤーが他オブジェクトの背後にいればレイとヒットしないようにする。
  • レイがプレイヤーとヒットしたら、追跡者を追跡モードに切り替える。

こういった多段階判定なら、レイキャストの回数を節約しつつ「プレイヤーが物陰に隠れていれば追跡者には見つからない」というような精密な視界判定ができそうです。

追記

なるほど、BoxCastがそのように設定されていればうまくいきそうですね。
複数レイが1本のBoxCastに置き換わったことで、もしかすると下図のようにプレイヤーにとって甘めの判定になってしまうかもしれませんが、ゲームデザインによっては(プレイヤーを見逃しても構わない、あるいはそもそも図のような状況にはならないようにしてある、など)問題ないかと思います。
BoxCast

投稿2018/01/24 21:07

編集2018/01/25 22:46
Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

japomondo

2018/01/25 02:16

またもご回答いただき本当にありがとうございます。大変恐縮ですが、ただいま出先ですのでお返事が遅れてしまうことをお許しください。
japomondo

2018/01/25 15:47

Bongo様、お返事が遅くなり申し訳ございません。 本件、Physics.BoxCastの引数に意図しているものとは異なる値を与えていたことが原因でした。。正コードを追記したのですが、当初のコードの引数は2点おかしい部分がありました。 1つ目が、最初の引数でRayの光源となるVector3型の値で、誤って追跡者の子オブジェクトの15/2f前方になっていました。 2つ目が、最後の引数でRayの長さを規定するFloat型の値を0としていたので、そもそもRayが発生していませんでした。。 ご助言いただきました点に関しては、今回に関しては考慮せずとも問題無さそうでした。 以上です。本件もご助言いただき、誠にありがとうございました。
japomondo

2018/01/26 02:18

プレイヤーの起立時としゃがみ時を考慮して2つのBoxCastを飛ばすことにしたので、上下の高さに関しては対応できているのですが、それでもBongo様ご指摘のような場合にはプレイヤーを捉えられないですね。。 上下それぞれ今より横幅が短いものを2つずつBoxCastを飛ばせば精度は上がりそうですが、それだと4つになってしまって結局通常レイを複数飛ばすのと負担量は変わらなそうですし、ひとまずルートを工夫するしかないのかなぁと思っています。
Bongo

2018/01/26 02:49

負荷と正確さのバランス取りはなかなか難しいですね。 他の思い付きとしては「追跡者の正面に大きなボックスをキャストする」代わりに、「追跡者の向きはひとまず考慮せず、追跡者の位置からプレイヤーの方角へ小さなボックス(またはスフィア)をキャストする」「もしプレイヤーにヒットしたら、さらに追跡者から見たプレイヤーの距離・方角から追跡者の前方にいるかを判定する」なんていうのもアリかと思いますが、どうでしょう。 ※「BoxCastによる可視判定」と「位置関係による前方判定」のどちらが高負荷になるかちゃんと調べたわけではないですが、順序を逆にして「位置関係による前方判定」→「BoxCastによる可視判定」にした方が、前方判定ではじかれた場合はBoxCastが行われなくなるので、負荷軽減になるかもしれないですね。
japomondo

2018/01/26 03:32

なるほどですね、そもそもですがUniRxを使って判定するようにしたため負荷量は小さくなっているはずなので、どの方法が最適か色々調べてみたいと思います。懇切丁寧にアドバイスいただき感謝いたします。
guest

0

つまりは「監視エリアを設定したい」ということかなと理解したのですが、あってますでしょうか?

もしそれであれば、該当位置に「is Trigger」をオンにしたBoxColliderを持つ不可視オブジェクトを該当箇所に配置しておき、そのオブジェクトにユーザが「触れた」瞬間に追跡を開始、監視エリアからユーザが離脱したら追跡モードを終了、としたら実現できるかなと思ったのですがいかがでしょうか?

投稿2018/01/24 23:16

edo_m18

総合スコア2283

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bongo

2018/01/25 00:07

追跡者の子として前方にトリガー領域を持たせれば、追跡者の移動に合わせて判定領域も動いてくれるので、CheckBox領域を自前で求めるよりもコードがシンプルになって良さそうですね。
japomondo

2018/01/25 02:19

コメントいただき誠にありがとうございます。少々お返事が遅れてしまいそうなので、取り急ぎお礼申し上げます。
japomondo

2018/01/25 02:30

edo_m18様、「監視エリアを設定したい」というご認識で間違いありません。 ただ、「is Trigger」をオンにしたBoxColliderで実現しようとすると、例えばプレイヤが車の陰に隠れている場合などでも、車を通り越してプレイヤのコライダにヒットしてしまい追跡モードがオンになってしまうため、今回は最適ではないと判断したのでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問