今回はUnity2Dでボールをはじく時のボールの軌道を表示してみます。
はじめに
Unityのバージョンは2021.3.14f1です。
下記のようにボールが飛ぶ場所の軌道を表示してみます。
下記ではボールをはじくのを実装しています。今回はそれに軌道を加えたイメージです。
実装開始
Hierarchyで右クリック、「2DObject」→「Sprites」→「Square」と「Circle」を追加します。
SquareはGroundに名前を変更、スケール、色を変更してBoxCollider2Dをアタッチします。
CircleはBallに名前を変更、スケールを変更し、「CircleCollider2D」と「Rigidbody2D」をアタッチします。
ゲーム画面を下記のような感じにします。
スクリプトの作成
下記スクリプトを作成してBallにアタッチします。今回はボールを掴むのではなく、画面上でマウスドラッグすると動かすようにしたいのでUpdate内で実装。
using UnityEngine; public class BallShoot2 : MonoBehaviour { private Rigidbody2D _rb; private float power = 2.0f; private float maxPower = 5.0f; private Vector2 StartPos; private Vector2 EndPos; private void Start() { _rb = GetComponent<Rigidbody2D>(); } private void Update() { if (Input.GetMouseButtonDown(0)) StartPos = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition); if (Input.GetMouseButton(0)) EndPos = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition); if (Input.GetMouseButtonUp(0)) { Vector2 force = Vector2.ClampMagnitude((StartPos - EndPos), maxPower); _rb.AddForce(force * power, ForceMode2D.Impulse); } } }
実行してみると下記のようになります。
軌道表示を追加
軌道の表示を追加するのでBallにLineRendererを追加し、Widthを変更しておきます。
スクリプトは下記に変更。
using UnityEngine; public class BallShoot2 : MonoBehaviour { private Rigidbody2D _rb; private LineRenderer _lr; private float power = 2.0f; private float maxPower = 5.0f; private Vector2 StartPos; private Vector2 EndPos; private Vector2 force; private void Start() { _lr = GetComponent<LineRenderer>(); _rb = GetComponent<Rigidbody2D>(); } private void Update() { if (Input.GetMouseButtonDown(0)) { _rb.velocity = Vector3.zero; _rb.isKinematic = true; StartPos = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition); } if (Input.GetMouseButton(0)) { EndPos = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition); force = Vector2.ClampMagnitude((StartPos - EndPos), maxPower) * power; Vector2[] trajectory = Plot(_rb, (Vector2)transform.position, force, 400); _lr.positionCount = trajectory.Length; Vector3[] positions = new Vector3[trajectory.Length]; for (int i = 0; i < trajectory.Length; i++) { positions[i] = trajectory[i]; } _lr.SetPositions(positions); } if (Input.GetMouseButtonUp(0)) { _rb.isKinematic = false; _rb.AddForce(force, ForceMode2D.Impulse); } } private Vector2[] Plot(Rigidbody2D rigidbody, Vector2 pos, Vector2 force, int steps) { Vector2[] results = new Vector2[steps]; float timestep = Time.fixedDeltaTime / Physics2D.velocityIterations; Vector2 gravityAccel = Physics2D.gravity * rigidbody.gravityScale * timestep * timestep; float drag = 1f - timestep * rigidbody.drag; Vector2 moveStep = force * timestep; for (int i = 0; i < steps; i++) { moveStep += gravityAccel; moveStep *= drag; pos += moveStep; results[i] = pos; } return results; } }
プロット部分は下記の記事を参考にしてます。(というかほぼそのまま)
サイトにも書いてあるけど、400個ポイントしているので一つ実装するのは問題ないけど、多くの実装には向かない感じですね。