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

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

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

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

Unity

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

Q&A

解決済

1回答

1717閲覧

地形Waypointに沿った弾丸の軌道を実装したい

Fou8A

総合スコア4

Unity3D

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

Unity

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

0グッド

0クリップ

投稿2021/06/20 05:55

編集2021/06/23 01:14

前提・実現したいこと

現在、unityでカービィ64のようなWaypointをたどるタイプの疑似3Dスクロールの開発をしています
それに伴い、発射した弾丸がWaypointに沿うように移動するプログラムを開発したいのですが、本体に使っていたWaypointを辿るプログラムをそのまま使い回すと、発射した弾丸が何故か2つになり、その場で静止してしまいます(二発目以降はまっすぐにのみ飛んでいく(waypoint無視)
逆に、玉本体にプログラムを設定しなかった場合は突っかかる事はありませんが、Waypointに沿う事なくまっすぐ飛んでいきます
これはあくまで私個人の憶測なのですが、今使っているプログラムがinstanceのオブジェクトには対応していないと考えています
今後敵の操作等もプレハブで発生させたものをWaypointで管理したいのでかなり重大な問題です
WaypointをInstanceに適用することはできないのでしょうか

発生している問題・エラーメッセージ(弾丸にメソッド適用時のみ)

NullReferenceException: Object reference not set to an instance of an object LineTrace.DirectionController2d.set_direction (LineTrace.Direction value)

該当のソースコード

キャラ本体側のスクリプト

using System.Collections; using System.Collections.Generic; using UnityEngine; using LineTrace; public class nita2dmove : MonoBehaviour { public DirectionController2d controller; public float speed; private Rigidbody rb; //キャラクターのコライダ private CapsuleCollider myCollider; private bool isGrounded; private float bulletspeed = 500f;//弾速 //ジャンプ力 [SerializeField] private float jumppower = 5f; private Vector3 velocity; // Start is called before the first frame update [SerializeField] private GameObject bulletPrefab; private float power = 10f; public Transform shotpoint;//弾丸発射地点 void Start() { rb = GetComponent<Rigidbody>(); myCollider = GetComponent<CapsuleCollider>(); controller.direction = Direction.front; } // Update is called once per frame void Update() { CheckGround(); Jump(); Move(); Fire(); } private void Move() { if (Input.GetKey(KeyCode.LeftArrow)) { // 向きを設定する controller.direction = Direction.back; rb.MovePosition(transform.position + controller.forward * speed * Time.deltaTime); } else if (Input.GetKey(KeyCode.RightArrow)) { // 向きを設定する controller.direction = Direction.front; rb.MovePosition(transform.position + controller.forward * speed * Time.deltaTime); //controller.forward*speed=velocity } } private void Jump(){ if (isGrounded) { if (Input.GetButtonDown("Jump")) { isGrounded = false; rb.velocity = new Vector3(rb.velocity.x, jumppower, rb.velocity.z); } } } private void Fire() { if (Input.GetKeyUp(KeyCode.Z)) { var bulletInstance = Instantiate<GameObject>(bulletPrefab, shotpoint.position, shotpoint.rotation); bulletInstance.GetComponent<Rigidbody>().AddForce(bulletInstance.transform.position+controller.forward * bulletspeed); Destroy(bulletInstance, 5f); } } private void CheckGround() { if (isGrounded) { return; } if (Physics.CheckSphere(rb.position, myCollider.radius - 0.1f, LayerMask.GetMask("Ground"))) { isGrounded = true; velocity.y = 0f; }else{ isGrounded = false; } } }

Waypointに沿って方向転換するスクリプト

using UnityEngine; using UniRx; using UniRx.Triggers; namespace LineTrace { public class DirectionController2d : MonoBehaviour { /// <summary> /// 正面ベクトル /// </summary> public Vector3 forward { get; private set; } private Direction mDirection; /// <summary> /// 向いている方向 /// </summary> public Direction direction { get { return mDirection; } set { mDirection = value; var f = (current.GetWayPointByDirection(mDirection) - transform.position); f.y = 0F; forward = f.normalized; } } private Line current; [SerializeField] private float distance = 0.1F; [SerializeField] private bool autoRotation = false; [SerializeField] private float rotateSpeed = 30F; // Use this for initialization void Start() { var lineManager = FindObjectOfType<LineManager>(); current = lineManager.GetLineAtNearDistance(transform.position); this.UpdateAsObservable() // 目的のポイントに接近したかどうか .Where( _ => Mathf.Abs(Vector2.Distance(transform.position.XZ(), current.GetWayPointByDirection(mDirection).XZ())) < distance) .Subscribe(_ => { var next = current.GetNextLineByDirection(mDirection); current = next ?? current; direction = mDirection; }); // 目的地の方向に自動で回転する if (autoRotation) { this.UpdateAsObservable() .Where(_ => forward != Vector3.zero) .Subscribe(_ => { var arrivedForward = forward.XZ(); var cross = transform.forward.XZ().Cross(arrivedForward); var dot = Vector2.Dot(transform.forward.XZ(), arrivedForward); if (dot < 0.98F) { transform.Rotate(Vector3.down, rotateSpeed * Mathf.Sign(cross) * Time.deltaTime); } }); } } } public enum Direction { front, back, none } }

適用すると悪化する弾丸側スクリプト

using System.Collections; using System.Collections.Generic; using UnityEngine; using LineTrace; public class protbsllet : MonoBehaviour { private DirectionController2d controller; private Vector3 velocity; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } }

試したこと

玉本体の回転固定と解除
玉本体の質量の変更
Waypointの位置の変更
玉本体にスクリプトの設定と解除

補足情報(FW/ツールのバージョンなど)

シーンから弾は取り除き済み
Waypointのスクリプト等は
Unityで3D横スクロールの挙動を考える
こちらのサイト様のものをほぼそのままお借りしています

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

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

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

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

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

sakura_hana

2021/06/22 00:20

DirectionController2dクラスのset_directionメソッドでエラーが出ていますが記載されていません。質問では省略しているなら記載してください。 現状の勘だと、2発出るのはシーン上にプレハブの元となるオブジェクトが存在しているせい。静止するのはNullReferenceExceptionエラーが出ているのでスクリプトが止まるせい。まっすぐ飛ぶのはまた別の要因かなと思います。
Fou8A

2021/06/23 01:12

set_directionエラーは一時期出ていたようなのですが現在の状態だと表示されていないので書きそびれていました…現在は一時的に発生していないだけの可能性もありますので発生し次第追記させていただきます プレハブ元のオブジェクトに関しましては一応発射する弾の元となったものは元々シーンから取り除き済みです
guest

回答1

0

ベストアンサー

まずエラーについてはDirectionController2ddirectionのSetter内でcurrentがNullになっているから引き起こっていると思います。


###問題点
キャラクターの移動は常にDirectionController2dforwardに進んでいます。だからルート通りに移動できます。
しかし、弾丸はどうでしょうか。

cs

1bulletInstance.GetComponent<Rigidbody>().AddForce(bulletInstance.transform.position+controller.forward * bulletspeed);

上記のようにRigidbody(物理演算)を使って瞬間的に撃ち出しています。
DirectionController2dがやるのはあくまでも「方向を教えてくれる」だけです。飛び出してしまった弾丸の軌道を変えたいなら、ちゃんとスクリプトで弾丸の飛び方まで面倒見てあげると良いかと思います。

やり方は色々あると思いますが、キャラクターが弾丸を撃つのではなく、弾丸がルート通り飛ぶという考え方でアプローチできると思います。

###弾丸の方向
まず弾丸にもDirectionController2dがついていると思うので、キャラクターと同じ方向情報を与えてやります

cs

1 private void Fire() { 2 if (Input.GetKeyUp(KeyCode.Z)) { 3 var bulletInstance = Instantiate<GameObject>(bulletPrefab, shotpoint.position, shotpoint.rotation); 4 bulletInstance.GetComponent<DirectionController2d>().direction = controller.direction; 5 Destroy(bulletInstance, 100f); // デバッグ用に秒を増やしてます 6 } 7 }

###弾丸自体に飛ばさせる
そして弾丸側には「与えられた方向にひたすら飛ぶ」という処理をやらせます。追尾ミサイルみたいなやつです。
キャラの移動で使っているようにDirectionController2dforwardが行くべきところなので、常にそこに向けてvelocityを設定します。

cs

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using LineTrace; 5 6public class protbsllet : MonoBehaviour { 7 public DirectionController2d controller; 8 Rigidbody rb; 9 // Update is called once per frame 10 private void Awake() { 11 controller = GetComponent<DirectionController2d>(); 12 rb = GetComponent<Rigidbody>(); 13 } 14 void Update() { 15 rb.velocity = controller.forward; 16 } 17} 18

###実践
waypoint3個だけなのでルートが荒いですが、ちゃんとルート通り弾丸が飛んでいます
イメージ説明

念の為補足しますが、これが最良のやり方というわけではありません。あくまでも一例としてご参考いただければと思います。

投稿2021/06/23 06:58

編集2021/06/23 07:01
hogefugapiyo

総合スコア3302

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

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

Fou8A

2021/06/23 12:01

試してみたころ、無事弾を動かすことが出来ました…ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問