今回は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個ポイントしているので一つ実装するのは問題ないけど、多くの実装には向かない感じですね。
