【Unity】Rigidbodyの弾道予測線をシュミレートする
前回の続きで、今回は撃つ側。
RigidbodyにAddForceを加えた場合の移動位置をシュミレートして表示する
なんていうのはみんなやっているようで、ググると大量に出てきます。
そのまま使わせて頂くのもOKですが、自分なりにまとめたソースもメモ。
Rigidbodyの移動を予測計算
using System.Collections; using System.Collections.Generic; using UnityEngine; /** * Rigidbodyにvecを加えた時の弾道をシュミレート。 */ public class BallSimulator : MonoBehaviour { [SerializeField] private GameObject _ballSimPrefab; // 何でもOK。予測位置を表示するオブジェクト private const int SIMULATE_COUNT = 20; // いくつ先までシュミレートするか private Vector3 _startPosition; // 発射開始位置 private List<GameObject> _simuratePointList; // シュミレートするゲームオブジェクトリスト void Start () { Init(); } void Update () { // デバッグ用に線を出してみる。必要無いなら無くても問題なし。 if (_simuratePointList != null && _simuratePointList.Count > 0) { for (int i = 0; i < SIMULATE_COUNT; i++) { if (i == 0) { Debug.DrawLine(_startPosition, _simuratePointList[i].transform.position); }else if (i < SIMULATE_COUNT) { Debug.DrawLine(_simuratePointList[i - 1].transform.position, _simuratePointList[i].transform.position); } } } } // 初期化 private void Init() { if (_simuratePointList != null && _simuratePointList.Count > 0) { foreach (var go in _simuratePointList) { Destroy(go.gameObject); } } // 位置を表示するオブジェクトを予め作っておく if (_ballSimPrefab != null) { _simuratePointList = new List<GameObject>(); for (int i = 0; i < SIMULATE_COUNT; i++) { var go = Instantiate(_ballSimPrefab); go.transform.SetParent(this.transform); go.transform.position = Vector3.zero; _simuratePointList.Add(go); } } } /** * 弾道を予測計算する。オブジェクトを再生成せず、位置だけ動かす。 * targetにはRigidbodyが必須です **/ public void Simulate(GameObject target , Vector3 _vec) { if (_simuratePointList != null && _simuratePointList.Count > 0) { // 発射位置を保存する _startPosition = target.transform.position; var r = target.GetComponent<Rigidbody>(); if (r != null) { // ベクトルはmassで割る Vector3 force = (_vec / r.mass); //弾道予測の位置に点を移動 for (int i = 0; i < SIMULATE_COUNT; i++) { var t = (i * 0.5f); // 0.5秒ごとの位置を予測。 var x = t * force.x; var y = (force.y * t) - 0.5f * (-Physics.gravity.y) * Mathf.Pow(t, 2.0f); var z = t * force.z; _simuratePointList[i].transform.position = _startPosition + new Vector3(x, y, z); } } } } }
発射する側は
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; /** * 弾を発射する */ public class BallShooter : MonoBehaviour { [SerializeField] private BallSimulator _ballSimurator; // 弾道予測線 [SerializeField] private Slider _powerSlider; // 力を変えるスライダー [SerializeField] private GameObject _shooterBase; // 土台 private Vector3 _firstPosition; private Rigidbody _rigidbody; private Vector3 _touchDownPos; private bool _isShot; // Use this for initialization void Start () { Init(); } // Update is called once per frame void Update () { if (!EventSystem.current.IsPointerOverGameObject()) { if (Input.GetMouseButtonDown(0)) { _touchDownPos = Input.mousePosition; } else if (Input.GetMouseButton(0)) { var tempPos = Input.mousePosition; Vector3 value = Vector3.zero; value.x = (_touchDownPos.x - tempPos.x); value.y = (_touchDownPos.y - tempPos.y); value.z = 0; _touchDownPos = tempPos; var qot1 = Quaternion.AngleAxis(value.x, new Vector3(0, 1, 0)); var qot2 = Quaternion.AngleAxis(value.y, new Vector3(1, 0, 0)); _shooterBase.transform.rotation *= qot1; this.transform.rotation *= qot2; } } Debug.DrawLine(this.transform.position, this.transform.position + this.transform.forward , Color.blue); // 発射中はシュミレートを止める if (!_isShot) { var vec = this.transform.forward * _powerSlider.value; _ballSimurator.Simulate(this.gameObject, vec); } } public void Init() { _firstPosition = this.transform.position; _rigidbody = this.GetComponent<Rigidbody>(); _rigidbody.isKinematic = true; _powerSlider.value = 10.0f; _isShot = false; } //-------------------------------------------------------------------------- // 発射(Buttonから呼ぶとか) public void Shoot() { _isShot = true; var vec = this.transform.forward * _powerSlider.value; _ballSimurator.Simulate(this.gameObject , vec); _rigidbody.isKinematic = false; _rigidbody.AddForce(vec, ForceMode.Impulse); } }
こんな感じでOK。
動かす
- 発射方向を変えるとそれに合わせて予測線も変わるか
- 発射する力を変えるとそれに合わせて予測線も変わるか
- massを変えると予測線も変わるか
- 予測線に沿って飛ぶか
この辺りに注目。
この次は
砲台を突然作り出したのはProbuIlderの勉強のため
今回でなんちゃって簡易砲台(作ろうとしているゲームでは砲台ではないんだけど)が出来上がったので、
次回からProBuilderを使用したステージ制作に入っていければいいな