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

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

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

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

Unity3D

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

Unity

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

Q&A

解決済

3回答

3471閲覧

Unityで、一番近くの敵に自動で弾を撃つタレットをつくりたいのですが…

thaya

総合スコア4

C#

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

Unity3D

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

Unity

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

0グッド

1クリップ

投稿2020/02/19 10:10

現在、「指定した1つのオブジェクトに向かって弾を撃つ」スクリプトと「指定したタグを持つオブジェクトの中で一番近いものを見つける」スクリプトを拾ったので、どうにかくっつけて「指定したタグをもつオブジェクトの中で一番近いものに向かって弾を撃つ」スクリプトにしたいのですが、うまく組み合わせることができません。

以下の二つを組み合わせて使う方法、あるいは他の方法でも今回やりたいことが実現できる方法があれば教えてください。

####【指定した1つのオブジェクトに向かって弾を撃つ】

using System.Collections; using System.Collections.Generic; using UnityEngine; public class LookAt_Pod : MonoBehaviour { public GameObject BulletPrefab; public float bulletSpeed; public float span = 1f; private int timeCount = 0; private GameObject targetObj; // 注視したいオブジェクト void Update() { this.transform.LookAt(targetObj.transform); timeCount += 1; if (timeCount > span) { timeCount = 0; // 敵の弾を生成する GameObject Bullet = Instantiate(BulletPrefab, transform.position, Quaternion.identity); Rigidbody BulletRb = Bullet.GetComponent<Rigidbody>(); // 弾をforwardに飛ばす BulletRb.AddForce(transform.forward * bulletSpeed); // 3秒後に弾を削除する。 Destroy(Bullet, 3.0f); } } }

####【指定したタグを持つオブジェクトの中で一番近いものを見つける】

GameObject SerchEnemy(string Enemy) { float dis = 0; //距離保存用 float nearDis = 0; //最も近いオブジェクトの距離 GameObject targetObj = null; //オブジェクト // 指定したタグのオブジェクトをすべて取得する foreach (GameObject obj in GameObject.FindGameObjectsWithTag(Enemy)) { // 敵との距離を計算 dis = Vector3.Distance(obj.transform.position, transform.position); // より近いオブジェクトか、距離が0のオブジェクトなら更新 if (nearDis > dis || dis == 0) { nearDis = dis; // 距離を保存 targetObj = obj; // ターゲットを更新 } } //最も近かったオブジェクトを返す return targetObj; }

よろしくお願いいたします。

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

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

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

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

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

guest

回答3

0

LookAt_Pod側にSetTargetObj関数を実装し、
SerchEnemyの返り値を渡す感じじゃ無理なのでしょうか?

C#

1LookAt_Pod pod; 2EnemyManager enemyManager; 3 4pod.SetTargetObj(enemyManager.SerchEnemy());

また、単純にLookAt_PodクラスにSerchEnemy関数を実装しちゃえば
こんな感じでできそう

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class LookAt_Pod : MonoBehaviour 6{ 7 public GameObject BulletPrefab; 8 public float bulletSpeed; 9 public float span = 1f; 10 private int timeCount = 0; 11 private GameObject targetObj; // 注視したいオブジェクト 12 13 void Update() 14 { 15 this.transform.LookAt(SerchEnemy().transform); 16 17 timeCount += 1; 18 19 if (timeCount > span) 20 { 21 timeCount = 0; 22 // 敵の弾を生成する 23 GameObject Bullet = Instantiate(BulletPrefab, transform.position, Quaternion.identity); 24 25 Rigidbody BulletRb = Bullet.GetComponent<Rigidbody>(); 26 27 // 弾をforwardに飛ばす 28 BulletRb.AddForce(transform.forward * bulletSpeed); 29 30 // 3秒後に弾を削除する。 31 Destroy(Bullet, 3.0f); 32 } 33 } 34 35 GameObject SerchEnemy(string enemy) 36 { 37 // 省略 38 } 39 40}

でもこれ、懸念点があるとすれば、
LookAt_Podクラスが複数あると、
複数のLookAt_Podが全員、敵を全検索してしまうので、
やはりSerchEnemy関数はEnemyManagerのようなもので持っておいて、
LookAt_Podにセットする形がふさわしいかなと思います!

投稿2020/02/19 10:17

編集2020/02/19 10:22
MasujimaRyohei

総合スコア422

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

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

thaya

2020/02/19 14:19

丁寧にいろいろなご提案をいただき、誠にありがとうございます。 「EnemyManager」などを作って管理する方法はとてもよさそうですが、初心者すぎて結局組み込むことは叶いませんでした… もう少しプログラミングを理解して、ちゃんと扱えるようになったら活用させていただきたいと思います。
MasujimaRyohei

2020/02/20 02:46

2つ目の方法でもできませんでしたか?
thaya

2020/02/20 14:08 編集

2つ目にご提示いただいた方法は、"Enemy"を狙ってほしい場合は、 this.transform.LookAt(SerchEnemy().transform); の()のところに"Enemy"を入れて this.transform.LookAt(SerchEnemy("Enemy").transform); みたいにして使用するのでしょうか? 何か入れないと LookAt_Pod.SerchEnemy(string)' の必要な仮パラメーター 'Enemy' に対応する特定の引数がありません。 というエラーになってしまいます。 "Enemy"と入れたとしても、エラーなくゲームが再生できるものの、foeward方向に弾を飛ばすだけで求めていた動きはしてくれませんでした…
MasujimaRyohei

2020/02/21 02:23

> LookAt_Pod.SerchEnemy(string)' の必要な仮パラメーター 'Enemy' に対応する特定の引数がありません。 こちらはあなたの作った通りstring型の引数を渡してあげてください。 今回、この二つのスクリプトはきちんと動いている、という認識でしたが、 それは合っていますでしょうか? あと、タグの処理を含んでいるので、敵のオブジェクトにきちんとEnemyタグがついているかどうかも確認お願いいたします!
thaya

2020/02/21 17:52

すみません、スクリプトがちゃんと動くかどうかもテストしていませんでした。 【指定した1つのオブジェクトに向かって弾を撃つ】のほうは動作しますが、【指定したタグを持つオブジェクトの中で一番近いものを見つける】のほうは拾い物ののスクリプトをそのままコピペしただけです。 http://hellomoneyworld.seesaa.net/article/449510462.html ブログに書くくらいだから、エラーもでてないし当然動作しているんだろうと、安易に思い込んでしまっていました。 Dbag.Logをうまく組み込んだりして、動作の確認をすることすら今の自分にはできないので、とりあえず質問してみれば答えがもらえるのかなと…考えが甘かったです… タグは一応ちゃんとついてます。
MasujimaRyohei

2020/02/25 02:17

一旦頑張って各機能が動くかどうかを試してみたから合成させたほうがいいですね これは単体テストっていうもので、 一つの機能ごとに動くことを確認しないと、 何が間違っているのかがわからないので手の出しようがなくなってしまうからです…!
guest

0

C#

1public class LookAt_Pod : MonoBehaviour 2{ 3 // (中略) 4 5 GameObject SerchEnemy(string Enemy) 6 { 7 // 中身は2つ目のコードと同じ 8 } 9 10 void Update() 11 { 12 targetObj = SerchEnemy("タグ名"); 13 14 // 続きは1つ目のコードと同じ 15 } 16}

投稿2020/02/19 10:18

fiveHundred

総合スコア9774

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

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

thaya

2020/02/19 13:04

ご回答いただき、ありがとうございます。 なるほど!とおもい、targetObj = SerchEnemy("タグ名"); を追加してみたのですが、あまりうまくいきませんでした。 visual studio側ではエラーになっていないので、スクリプトではなくインスペクターの内容などに不備があるのかもしれません… ちなみに、 GameObject targetObj = null; //オブジェクト と this.transform.LookAt(targetObj.transform); に対して NullReferenceException: Object reference not set to an instance of an object LookAt_Pod.Update のエラーが出ています。 もし、なにか改善案などがございましたら、ご教授いただけますと幸いです。
fiveHundred

2020/02/19 13:20

おそらくですが、「GameObject.FindGameObjectsWithTag(Enemy)」で1つも見つからなかったのが原因では無いかなと思います。 敵のオブジェクトが存在しているかどうか、敵のオブジェクトにタグが設定しているかを確認してみてください。 もし、敵が存在しない時があるのであれば、場合分けをする必要があります。
thaya

2020/02/19 13:36

なるほど、敵がずっといる場合でないとこのスクリプトではダメなんですね… 敵を最初からずっといる状態にしたら、 GameObject targetObj = null; //オブジェクト のほうのエラーは出なくなりました。 ありがとうございます。 しかし、敵を感知することができているのに、 this.transform.LookAt(targetObj.transform); のほうが機能しないのはどうしてなのでしょうか… なにかお気づきでしたら、よろしくお願いいたします。
fiveHundred

2020/02/19 13:41

「機能しない」というのは「NullReferenceExceptionが出てしまう」ということでしょうか?
thaya

2020/02/19 13:43

はい、そうです。 あいまいな書き方をしてしまって申し訳ありません。
fiveHundred

2020/02/19 13:46

そうであれば、見つからない場合はtargetObjはnullなので、その場合は(「this.transform.LookAt(targetObj.transform);」などの)処理をしない、ということをする必要があります。 (先ほど言った「場合分け」とはこういう意味です)
thaya

2020/02/19 14:07

正直ちゃんと理解できてはいませんが、自分がやりたかった「指定したタグをもつオブジェクトの中で一番近いものに向かって弾を撃つ」という動きが単純にふたつのスクリプトを組み合わせるだけでは、動作しないということはわかりました。 ちゃんと動かすためには、他にもいろいろと処理が必要なんですね… 何度も返信してくださって、ありがとうございます。
guest

0

自己解決

https://blog.beatdjam.com/entry/2014/10/22/032751
このサイトに載っていたスクリプトを使用することで、やりたかった動きを実現することができたので、自己解決ということにさせていただきたいと思います。

回答やアドバイスをくださった方々、ありがとうございました。
とても参考になりました。

今回つくったタレットは、範囲の指定がなくシーン内の対象タグを持つオブジェクトをすべて狙ってしまうので、実際にゲームで使用するためには、もう一工夫必要だと思いますが、自分と同じようなものをつくりたいと思った初心者の方のためにコードを置いておこうと思います。

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class LookAt_Enemy : MonoBehaviour 6{ 7 public GameObject BulletPrefab; 8 public float bulletSpeed; 9 public float span = 1f; 10 private int timeCount = 0; 11 12 private GameObject nearObj; //最も近いオブジェクト 13 private float searchTime = 0; //経過時間 14 15 // Use this for initialization 16 void Start() 17 { 18 //最も近かったオブジェクトを取得 19 nearObj = serchTag(gameObject, "Enemy"); 20 } 21 22 // Update is called once per frame 23 void Update() 24 { 25 26 //経過時間を取得 27 searchTime += Time.deltaTime; 28 29 if (searchTime >= 0.1f) 30 { 31 //最も近かったオブジェクトを取得 32 nearObj = serchTag(gameObject, "Enemy"); 33 34 //経過時間を初期化 35 searchTime = 0; 36 } 37 38 if (nearObj == null) 39 { 40 this.transform.rotation = Quaternion.identity; //敵がいない場合は回転をリセット 41 } 42 else 43 { 44 //対象の位置の方向を向く 45 transform.LookAt(nearObj.transform); 46 47 timeCount += 1; 48 49 if (timeCount > span) 50 { 51 timeCount = 0; 52 // 敵の弾を生成する 53 GameObject Bullet = Instantiate(BulletPrefab, transform.position, Quaternion.identity); 54 55 Rigidbody BulletRb = Bullet.GetComponent<Rigidbody>(); 56 57 // 弾をforwardに飛ばす 58 BulletRb.AddForce(transform.forward * bulletSpeed); 59 60 // 3秒後に弾を削除する。 61 Destroy(Bullet, 3.0f); 62 } 63 } 64 } 65 66 //指定されたタグの中で最も近いものを取得 67 GameObject serchTag(GameObject nowObj, string tagName) 68 { 69 float tmpDis = 0; //距離用一時変数 70 float nearDis = 0; //最も近いオブジェクトの距離 71 GameObject targetObj = null; //オブジェクト 72 73 //タグ指定されたオブジェクトを配列で取得する 74 foreach (GameObject obs in GameObject.FindGameObjectsWithTag(tagName)) 75 { 76 //自身と取得したオブジェクトの距離を取得 77 tmpDis = Vector3.Distance(obs.transform.position, nowObj.transform.position); 78 79 //オブジェクトの距離が近いか、距離0であればオブジェクト名を取得 80 //一時変数に距離を格納 81 if (nearDis == 0 || nearDis > tmpDis) 82 { 83 nearDis = tmpDis; 84 targetObj = obs; 85 } 86 87 } 88 //最も近かったオブジェクトを返す 89 return targetObj; 90 } 91}

投稿2020/02/22 08:15

thaya

総合スコア4

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問