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

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

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

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

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

Q&A

解決済

2回答

10794閲覧

Unity3Dで自分が向いている方向に敵が入ってきたらロックオンする方法

natsumikan4729

総合スコア19

C#

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

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

0グッド

1クリップ

投稿2016/12/21 11:58

###前提・実現したいこと

イメージ説明
この図のように、自分の向いている方向からプラスマイナス30°の範囲に敵のオブジェクトが入ってきたら、それをロックオンして、なにかアクションを起こしたいと思っています。2Dではなく3Dです。
自分でもいろいろ試していますし、ネットでもいろいろ探しましたが、あまりうまくいきませんでした。
自分が主体で、敵のほうに向きをあわせるのではなく、敵がちょうど自分の視野内に入ったらなにかアクションを起こしたいと思っています。
もし範囲内に何体も敵がいたら、自分の向いている方向に近い鳥の方をロックオンしたいです。
あと、敵は空に飛んでいて、自分より高いところにいます。

###試したこと
下のコードのように、自分が操作しているキャラが向いている方向の単位ベクトルを出して、さらに、敵(鳥)と自分との単位ベクトルを出して、この二つのベクトルの角度差を求めて、その角度差が30°以内の場合にその鳥をロックオンする、みたいなことをやりましたが、あんまりうまくロックオンできませんでした...

###該当のソースコード

C#

1using UnityEngine; 2using System.Collections; 3 4public class My_Behavior : MonoBehaviour { 5 6 //鳥をロックオン用 7 private float lockCalcTimer; 8 9 void Start () { 10 lockCalcTimer = 0f; 11 } 12 13 void Update () { 14 15 //ロックオン関連 16 lockCalcTimer += Time.deltaTime; 17 if (lockCalcTimer > 0.5f) { 18 lockCalcTimer = 0f; 19 //ターゲット格納(Birdタグをしているオブジェクト) 暫定的に全オブジェクトを対象 20 GameObject[] allBird = GameObject.FindGameObjectsWithTag ("Bird"); 21 22 //自分自身が向いている方向の単位ベクトルを取得 23 float angleDir = this.transform.eulerAngles.y * (Mathf.PI / 180.0f); 24 Vector3 dir = new Vector3 (Mathf.Cos (angleDir)*0.1f, 0f, Mathf.Sin (angleDir)*0.1f); 25 26 //Vector3.Distance(a,b) -> aとbの間の距離を返す 27 foreach (GameObject obj in allBird) { 28 29 //対象の鳥の座標を取得 30 Vector3 birdV3 = obj.transform.position; 31 32 //鳥と自分との距離 33 float tmpDis = Vector3.Distance (obj.transform.position, this.transform.position); 34 35 //鳥と自分との単位ベクトル 36 Vector3 tmpV3 = (obj.transform.position - this.transform.position).normalized; 37 Vector3 tmpV2 = new Vector3 (tmpV3.x, 0f, tmpV3.z);//高さyを無視する 38 39 //向いている方向のベクトルと鳥と自分のベクトルの角度差 40 float angle = Vector3.Angle (dir, tmpV2); 41 42 //自分がどこまで遠く見えるか 43 float canSeeDis = 100f; 44 45 //自分がどの角度まで見えるか 46 float canSeeDir = 30f; 47 48 //向いている方向に+30度or-30度の範囲内に鳥がいるかどうかを確認 49 //鳥と自分の距離を確認 50 if (angle < canSeeDir && tmpDis < canSeeDis) { 51 Debug.Log ("ロックオン " + obj.name); 52 } 53 } 54 } 55 56 } 57} 58

###補足情報(言語/FW/ツール等のバージョンなど)
unity5.4 C#

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

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

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

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

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

ishi9

2016/12/22 02:16

y情報を意図的に消しているようですが、xz平面の2D上での判定をしたいということでいいのでしょうか?
natsumikan4729

2016/12/22 02:32

敵の方が自分が操作しているキャラよりも高いところにあるため、y座標があると、ベクトルで角度差を求めるのがちょっと難しくなるのかなと思ってy情報を消しました。
guest

回答2

0

ベストアンサー

最終的には3D的な判定をしたいのですかね?
一応、そっち方向で回答してみます。xz平面の2Dのままの方がいいならy情報消すだけなのでそうしてくてださい。
適当に直接書いただけなので、ちょっと文法ミスはあるかもしれませんが、以下のような感じでしょうか

C#

1Vector3 eyeDir = this.transform.foward; // プレイヤーの視線ベクトル。fowardが正しいかはモデルの配置等にも影響するので自分で正しいものを入れてください 2Vector3 playerPos = this.transform.position; // プレイヤーの位置 3Vector3 enemyPos; // 敵の位置 4 5float angle = 30.0f; 6 7// プレイヤーと敵を結ぶ線と視線の角度差がangle以内なら当たり 8if (Vector3.Angle((enemyPos - playerPos).normalized, eyeDir) <= angle) 9{ 10 // 範囲内の処理 11}

追記:
あ、後、距離がありましたね。そっちは特に問題無いと思いますが一応

C#

1if (Vector3.Angle((enemyPos - playerPos).normalized, eyeDir) <= angle 2 && Vector3.Distance (enemyPos, playerPos) <= distance) 3{ 4 // 範囲内の処理 5}

投稿2016/12/22 03:07

編集2016/12/22 03:11
ishi9

総合スコア1294

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

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

natsumikan4729

2016/12/22 08:45

ご回答ありがとうございます!! 解決できました! ありがとうございますorz !! もうひとつ、もし範囲内に二匹以上の敵が入っていて、近い方の敵(または向いている方向により近い敵)をロックオンしたいときって、どうすればいいですか?
ishi9

2016/12/22 09:45

Linqを使えば簡単です。使う時は「using System.Linq;」を宣言しておくのを忘れずに。 前準備 // こんなのを用意しておいて、ループ処理内でロックオンした敵はこの中に随時Addする var inRangeList = new List<GameObject>(); 後はループを抜けたら以下の処理を呼び出します。空の場合もあるので、Listのサイズが0の場合はスキップしてください。 // プレイヤーと敵の距離を近い順に並べ、その先頭(つまり一番近い敵)だけを取ってくる GameObject nearestEnemy = inRangeList.OrderBy(p => Vector3.Distance (p.transform.position, playerPos)).First(); 距離の代わりにangleを入れれば最も近い角度の敵を取得できます。 また、First()の代わりにToList()を呼べば単に並び替えるだけなので、近い順に何番目まで~なんて処理もできます。
natsumikan4729

2016/12/23 05:39

ishi9さん 丁寧な回答ありがとうございました! いろいろとてもたすかりました!! またの機会があればよろしくお願いします。
guest

0

数学どころか算数苦手なんであれですけど、その視界の範囲の形に添ったcollider(Mesh Collider)をくっつけて判定するというのはダメですか?w

投稿2016/12/21 13:44

turbgraphics200

総合スコア4267

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

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

natsumikan4729

2016/12/22 02:33

ご回答ありがとうございます。 今困っていることは、視界の範囲がうまく設定できないことです… なので、まだそれからのことができません…
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問