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

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

新規登録して質問してみよう
ただいま回答率
85.51%
Unity

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

Q&A

1回答

4079閲覧

[Unity2D]偏差射撃について

shorter

総合スコア13

Unity

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

0グッド

1クリップ

投稿2017/05/10 15:15

編集2022/01/12 10:55

###実現したいこと
上方向に高く飛ぶプレイヤーに対して、プレイヤーの真横を平行移動する敵が偏差射撃をする機能を実現したいと考えています。

###現在の状況
・敵のY座標にプレイヤーのY座標を代入することで、敵がプレイヤーの真横を平行移動するようにしています。

・偏差射撃の予測位置として、プレイヤーの現在位置に速度ベクトルを加えた座標に敵を向けています。

###行き詰まっていること
上記の状態で弾を発射したところ、プレイヤーと敵が弾を置き去りにしてしまったので、その問題を解消するためにプレイヤーのフレーム毎の上昇値を弾の座標に加えました。弾が置き去りになることは無くなったのですが、このままだと弾がプレイヤーと同じ距離だけ上昇してしまうので、衝突することなく弾が過ぎ去ってしまいます。

弾がちょうどプレイヤーに衝突するよう、弾の上昇値を変えなければならないとは思っているのですが、具体的にどの要素が必要なのかが分かっていない状況です。

ヒントやアドバイス、解決法の提案等、何でも構いませんので、お答え頂きたく思います。
よろしくお願い致します。

###追記
文章のみの質問で申し訳ありませんでした。

以下に当問題に関係があると考えているスクリプトを添付させて頂きます。
読みにくいコードかとは思いますが、よろしくお願い致します。

c#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class PlayerParameter : MonoBehaviour { 6 7 //PlayerのRigidbody2D 8 private Rigidbody2D rb2d; 9 //Playerの速度 10 private float v = 0.0f; 11 //Playerの速度ベクトル 12 private Vector3 vVector; 13 //Playerの現在位置 14 private Vector3 nowPos; 15 //Playerの前フレームの位置 16 private Vector3 prevPos = Vector3.zero; 17 //Playerの移動ベクトル 18 private Vector3 moveVec = Vector3.zero; 19 20 // Use this for initialization 21 void Start () { 22 //Rigidbody2Dコンポーネントを取得 23 rb2d = this.GetComponent<Rigidbody2D> (); 24 } 25 26 // Update is called once per frame 27 void Update () { 28 //Playerの現在位置を格納 29 nowPos = this.transform.position; 30 //Playerの速度値を格納 31 v = rb2d.velocity.magnitude; 32 //Playerの速度ベクトルを格納 33 vVector = rb2d.velocity; 34 //Playerの移動ベクトルを格納 35 moveVec = nowPos - prevPos; 36 //Playerの現在位置を前フレームの位置にする 37 prevPos = nowPos; 38 } 39 40 //Playerの速度を返す関数 41 public float GetVelocity(){ 42 return v; 43 } 44 45 //Playerの速度ベクトルを返す関数 46 public Vector3 GetVelocityVector(){ 47 return vVector; 48 } 49 50 //Playerの移動ベクトルを返す関数 51 public Vector3 GetMoveVector(){ 52 return moveVec; 53 } 54}

c#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Enemy : MonoBehaviour { 6 7 //標的(Player) 8 private GameObject playerObj; 9 //自分(Enemy)の座標 10 private Vector3 mPos; 11 //Playerの座標 12 private Vector3 pPos; 13 //Playerの移動予測座標(偏差射撃のため) 14 private Vector3 forecastPos; 15 //Playerの速度 16 private float p_velocity; 17 //PlayerとEnemy間の距離 18 private float p_distance; 19 20 // Use this for initialization 21 void Start () { 22 //Playerオブジェクトを取得 23 playerObj = GameObject.FindWithTag ("Player"); 24 } 25 26 // Update is called once per frame 27 void Update () { 28 //PlayerにアタッチされているPlayerParameterスクリプトを参照 29 PlayerParameter pp = playerObj.GetComponent<PlayerParameter> (); 30 //Shootingスクリプトを参照 31 Shooting st = GetComponent<Shooting> (); 32 //自分(Enemy)の座標を取得 33 mPos = transform.position; 34 //Playerの座標を取得 35 pPos = playerObj.transform.position; 36 //Playerの速度を格納 37 p_velocity = pp.GetVelocity(); 38 //PlayerとEnemy間の距離を格納 39 //p_distance = Vector3.Distance(mPos, pPos); 40 //Playerの速度を送る 41 st.SetPlayerVelocity (p_velocity); 42 //Playerの予測移動位置を格納 43 forecastPos = pPos + pp.GetVelocityVector(); 44 //targetを向く 45 transform.rotation = Quaternion.FromToRotation( Vector3.up, forecastPos); 46 //PlayerのY座標を取得し、自分(Enemy)の座標に反映(=Playerと平行移動) 47 mPos.y = pPos.y; 48 transform.position = mPos; 49 } 50}

c#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5//Rigidbody2Dコンポーネントを必須にする 6[RequireComponent(typeof(Rigidbody2D))] 7public class Shooting : MonoBehaviour { 8 9 //Bulletプレハブ 10 [SerializeField] 11 private GameObject muzzle; 12 //弾を撃つ間隔 13 [SerializeField] 14 private float shotDelay = 1f; 15 //弾の速度 16 [SerializeField] 17 private float bulletSpeed = 5f; 18 //Playerの速度 19 private float p_velocity = 0f; 20 21 // Update is called once per frame 22 void Update () { 23 24 } 25 26 // Startメソッドをコルーチンとして呼び出す 27 IEnumerator Start () 28 { 29 while (true) { 30 //Debug.Log (GetBulletSpeed()); 31 32 // 弾を敵オブジェクトと同じ位置/角度で作成 33 Instantiate (muzzle, transform.position, transform.rotation); 34 // shotDelay秒待つ 35 yield return new WaitForSeconds (shotDelay); 36 } 37 } 38 39 //Enemyの速度を加算した弾の速度を返す 40 public float GetBulletSpeed(){ 41 return bulletSpeed; 42 } 43 44 //Playerの速度をセットする関数 45 public void SetPlayerVelocity(float v){ 46 p_velocity = v; 47 } 48 49 //Playerの速度を取得する関数 50 public float GetPlayerVelocity(){ 51 return p_velocity; 52 } 53} 54

c#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5//Rigidbody2Dコンポーネントを必須にする 6[RequireComponent(typeof(Rigidbody2D))] 7public class Bullet : MonoBehaviour { 8 9 //敵オブジェクト 10 private GameObject eneObj; 11 //Playerオブジェクト 12 private GameObject playerObj; 13 14 // Use this for initialization 15 void Start () { 16 //Playerオブジェクトを取得 17 playerObj = GameObject.FindWithTag ("Player"); 18 //Enemyオブジェクトを取得 19 eneObj = GameObject.FindWithTag ("Enemy"); 20 //EnemyオブジェクトのShootingスクリプトを参照 21 Shooting st = eneObj.GetComponent<Shooting> (); 22 //弾を発射する 23 GetComponent<Rigidbody2D> ().AddForce (transform.up.normalized * st.GetBulletSpeed(),ForceMode2D.Impulse); 24 } 25 26 // Update is called once per frame 27 void Update () { 28 //PlayerにアタッチされているPlayerParameterスクリプトを参照 29 PlayerParameter pp = playerObj.GetComponent<PlayerParameter> (); 30 //Playerの移動ベクトルを加える 31 transform.position += pp.GetMoveVector (); 32 } 33}

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

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

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

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

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

edo_m18

2017/05/10 15:26

文章だけだとどこに問題があるのか(ロジックなのか、考え方なのか、そもそもプログラム的なミスなのかなど)分からないので、今書いているコードも合わせて示していただけると回答がしやすくなると思いますよ。
shorter

2017/05/10 15:49

修正依頼、ありがとうございます。ただいま当問題に関係があると考えているソースコードを追加させて頂きました。
Bongo

2017/05/21 11:51

意図する動きを確認させていただきたいのですが、今回ご提示のShoothingクラスの弾オブジェクトをインスタンス化している箇所に「// 弾をプレイヤーと同じ位置/角度で作成」とありますが、このクラスはプレイヤーが弾を撃つためのクラスなのでしょうか?今回問題とされているのは「敵がプレイヤーを狙って(動きを予測して)弾を撃つように作ったが、敵から発射された弾は意図通りの動きにならない」ということかと思ったのですが、このShootingクラスは敵が弾を撃つ場合にも使用されているのでしょうか?
shorter

2017/05/21 12:53

ご質問ありがとうございます。Shootingクラスに関してですが、Bongoさんの仰る通り、「敵がプレイヤーに対して弾を撃つ」ように作っています。ご指摘の「//弾をプレイヤーと同じ位置/角度で作成」は誤りのため、先ほど「プレイヤー」を「敵オブジェクト」に修正させて頂きました。このShootingクラスは、敵にのみアタッチされており、プレイヤーが弾を撃つことはありません。分かりにくくなってしまい申し訳ありません。
Bongo

2017/05/21 13:05

ご修正ありがとうございます。Shootingクラスは敵が射撃する際に使われているようですね。たびたびすみませんが、もう一点伺いたいのですが、ShootingクラスはEnemyクラスの子であり、Enemyが移動・回転すると同じ動きをするように作られているのでしょうか。それとも両者に親子関係はなく、おのおの独立しているのでしょうか。
Bongo

2017/05/21 13:09

おっとすみません、投稿タイミングでお返事を見逃してしまいました。敵にアタッチされているのですね。この条件でもう少し考えてみます。
shorter

2017/05/21 13:37

ご質問ありがとうございます。ご質問の内容を私が勘違いしていないか心配なのですが、ShootingクラスとEnemyクラスには親子関係はなく、独立して作っているつもりです。どちらのスクリプトも敵オブジェクトにアタッチされており、Enemyクラスでは敵オブジェクトの向きを変え、Shootingクラスでは敵オブジェクトの向きに合わせて弾を生成、射撃しています。ご質問の意味を取り違えていたら申し訳ありません。
shorter

2017/05/21 13:48

Bongoさんの22:09のご投稿を見逃し投稿してしまいました。Bongoさんの仰る通り、ShootingクラスとEnemyクラスはそれぞれ敵オブジェクトにアタッチされています。重ね重ね申し訳ありません。
guest

回答1

0

おかしな動きの原因と関係あるかもしれないと思った箇所を挙げさせていただきます。
Bulletが新たに作られたとき、BulletのStartの中でGetComponent<Rigidbody2D> ().AddForce (transform.up.normalized * st.GetBulletSpeed(),ForceMode2D.Impulse);で初速度を与えているご様子ですが、Impulseは力積を意味し、その前の引数として与えるべきは弾の運動量の変化量になるかと思います。
試しにここのImpulseをVelocityChangeに変えてみて、さらにUpdateの中のtransform.position += pp.GetMoveVector ();はコメントアウトしてしまい、一旦Startで初速度を与えたら、Updateでむやみに動きを操作せずに物理計算エンジンが自動的に移動させるに任せてみるとどうなるでしょうか。
最初に「弾を置き去りにしてしまった」という動きをしたのも、弾の質量が大きすぎて実際の初速度がかなり小さくなってしまったためかもしれません。

[追記]
うっかりしておりました。ForceMode2DではVelocityChangeが使えなかったかもしれませんね。モードはImpulseのままにして、代わりにその前の引数にさらにBulletのRigidBody2Dのmassを掛けてみるといかがでしょう。

[さらに追記]
もしかしてBulletのRigidBody2DのisKinematicがオンになっている、ということはありませんでしょうか。もしそうだと、AddForceで力積を加えようとしても無効になるかもしれません。isKinematicを切るか、あるいはAddForceを使う代わりにRigidBody2Dのvelocityにtransform.up.normalized * st.GetBulletSpeed()をセットする(こちらなら多分いける、と思います...)、などの手段が必要かと思います。

投稿2017/05/22 02:48

編集2017/05/22 05:03
Bongo

総合スコア10807

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

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

shorter

2017/05/22 08:43

ご回答ありがとうございます。 追記に関してですが、Bongoさんの仰る通り、ForceMode2DではVelocityChangeが使えませんでした。また、BulletクラスのAddForceで、BulletのRigidBody2Dのmassを掛ける方法は以前試したことがあるのですが、意図した動きにはなりませんでした。 追追記に関してですが、現在使用しているUnity5.6には「isKinematic」項目が見受けられないのですが、「RigidBody2D > BodyType」が「Dynamic」となっているため、おそらくKinematic関連の問題はないと考えています。また、AddForceの代わりに「GetComponent<Rigidbody2D> ().velocity = transform.up.normalized * st.GetBulletSpeed();」を試してみたのですが、見た目上、AddForceによる動きと変わりがありませんでした。 また、「弾が置き去りになる」ことに関してですが、これは私のさじ加減の問題かもしれませんが、現仕様ではプレイヤーをAddForceによって2000~3000ほどの値で上昇させているため、物凄い速度(漠然とした表現で申し訳ありません)で移動するようになっており、それが原因だと決めつけていました。 この度、Bongoさんの推測や解決法案を受け、より様々な箇所に原因の可能性を疑う必要があると感じました。貴重なお時間を割いて頂き、誠にありがとうございました。 今後は現在の仕様の変更を視野に入れつつ、当問題について考えていこうと思います。
Bongo

2017/05/22 09:42 編集

タイプがDynamicなら、キネマティックに関しては大丈夫そうですね。 2000~3000となると、プレイヤーが100kgとしても30m/s、時速100kmあたりの速さの高速戦闘ということですか。 こうなると、弾が置き去りになったのはプレイヤーに対して弾が遅すぎる可能性も出てきますね。 質問者さんの「プレイヤーの移動ベクトルを加える」という発想はなかなかよさそうです。 敵もプレイヤーと同等の高速な動きをしており、その上に据え付けられた砲塔から弾を撃つわけですから、これも加味しないとならないでしょう。 つまり、今のコードにおいて「弾の速度ベクトル」とされているものに、さらに「弾を発射している敵の速度ベクトル」を加え、この二つの速度 ベクトルの和に対して弾の質量を掛けて力積ベクトルとし、それを弾生成時のAddForceに渡す...なんていうのはどうでしょうか。
shorter

2017/05/28 11:14

返信が遅れてしまい申し訳ありません。 Sceneビューで見ていると高速移動しているのですが、カメラをプレイヤーの子にしているため、ゲーム画面では背景などがなければ動いているように見えない状態となっています。 今のコードにおける「弾の速度ベクトル」というのは、ShootingクラスのbulletSpeedのことでしょうか。理解力が足りず勘違いしていましたら申し訳ありません。私の勝手な解釈ではありますが、弾生成時のAddForceの引数となっている「transform.up.normalized」にプレイヤーの速度ベクトルを加えてみたのですが、想定していた動きにはなりませんでした。 ※ご提示頂いた「弾を発射している敵の速度ベクトル」ですが、敵は自身の座標をプレイヤーの移動ベクトルを代入することで移動しているせいか、速度ベクトルが常に(0,0,0)だったため、プレイヤーの速度ベクトルを使用しました。
Bongo

2017/05/28 11:34

いえいえ、お気になさらずに。 先の回答で申し上げましたのは、弾の質量をmassとして、GetComponentで持ってきたプレイヤーオブジェクトをppとしますと、現状transform.up.normalized * st.GetBulletSpeed()となっている部分を((transform.up.normalized * st.GetBulletSpeed()) + pp.GetMoveVector()) * massとするという意図でした。このようになっていてもうまくいかなかったということでしょうか? もしそうでしたら、一つ確認したいのですが、もしかしてプレイヤーオブジェクトは毎フレームAddForceで加速していて、時間が経つにつれてプレイヤー(と敵とカメラ)の速度は上方向にどんどん大きくなっていたりしますか(つまり、一定の速度で飛んでいるわけではない)?この場合、「弾を発射した瞬間のプレイヤー速度ベクトル」を弾に与えても、プレイヤーが加速しているので弾が置き去りに(実際にはプレイヤーが上に逃げて)しまうかもしれません。
shorter

2017/05/28 15:24

私の勘違いで、ご提示頂いた「pp.GetMoveVector()」の部分を「pp.GetVelocityVector()」にしていた(他は合っていました)ので、「pp.GetMoveVector()」で試してみたのですが、うまくいきませんでした。 プレイヤーに上方向の力が加わるのは一度のみとなっています。ただ重力(GravityScaleは0.75)がかかっていますので、常に一定の速度で飛んでいる訳ではありませんが、速度が上がることはありません。
Bongo

2017/05/29 02:23

おっとすみません、GetVelocityVectorが秒速での速度ベクトルなので、GetMoveVectorよりそちらが適切ですね。それでもダメ、プレイヤーもほぼ等速で上昇しているとなると...あとは何でしょうか。何か思いついたらコメントします。すみません。 ※もし可能でしたら、そのダメな動きをGIFなどで見せていただけますでしょうか。お手持ちのソフトにそういったものがなければ結構です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問