今回はUnityで「弓で矢を飛ばす」のを実装してみます。マウスで弓を引き、離した時に矢を撃つ感じです。Part2では矢を飛ばすのを実装していきます。
はじめに
Unityのヴァージョンは2022.3.14f1です。Part1は下記です。
実装開始
Part1の続きから作成していきます。
矢を飛ばす
矢の画像を画面にセットして、「Rigidbody2D」を追加、Arrowという名前でスクリプトを作成して追加します。

作成した矢はプレハブ化しておきます。

プレハブ化をしたら元の矢を削除します。

スクリプトで矢を生成
Instantiateで矢を生成すると下記のように生成されるので変更していきます。

生成位置を「矢の後ろの位置」と「弦の真ん中」に合わせたいので、矢の画像を「SpriteEditor」で編集してPivotの位置を変更します。

Bowスクリプトを下記のように変更します。変更のない箇所は省略してあります。
using UnityEngine;
public class Bow : MonoBehaviour
{
[SerializeField] private Arrow ArrowPrefab;
private Arrow Arrow;
void Update()
{
Vector2 mousePos = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Input.GetMouseButtonDown(0))
{
startPos = mousePos;
isPull = true;
Arrow = Instantiate(ArrowPrefab);
SetArrowPos(Anchor.transform.position);
}
else if (Input.GetMouseButton(0))
{
Vector2 distance = Vector2.ClampMagnitude((mousePos - startPos), maxString);
Vector2 pos = (Vector2)Anchor.transform.position + distance;
StringRender(pos);
float angle = Mathf.Atan2(mousePos.y - startPos.y, mousePos.x - startPos.x);
transform.rotation = Quaternion.AngleAxis(angle * Mathf.Rad2Deg, Vector3.forward);
SetArrowPos(pos);
}
if (Input.GetMouseButtonUp(0))
{
isPull = false;
StringRender(Vector2.zero);
}
}
private void SetArrowPos(Vector2 pos)
{
Arrow.transform.position = pos;
Arrow.transform.rotation = this.transform.rotation;
}
}
パラメータにプレハブをセットします。

実行して下記のように矢が意図した場所に生成されたらOKです。

スクリプトの変更
次にArrowスクリプトの中身を下記に変更します。
using UnityEngine;
public class Arrow : MonoBehaviour
{
private Rigidbody2D rb;
private void Awake()
{
rb = GetComponent<Rigidbody2D>();
}
public void ArrowShot(Vector2 force)
{
rb.AddForce(force, ForceMode2D.Impulse);
}
}
Bowスクリプトの最終形は下記になります。
using UnityEngine;
public class Bow : MonoBehaviour
{
[SerializeField] private GameObject Top;
[SerializeField] private GameObject Bottom;
[SerializeField] private LineRenderer String1;
[SerializeField] private LineRenderer String2;
[SerializeField] private GameObject Anchor;
[SerializeField] private Arrow ArrowPrefab;
private Vector2 startPos;
private bool isPull;
private float maxString = 1.2f;
private float power = 8.0f;
private Arrow Arrow;
void Start()
{
isPull = false;
StringRender(Vector2.zero);
}
private void StringRender(Vector2 pos)
{
Vector2 TopPos = Top.transform.position;
Vector2 BottomPos = Bottom.transform.position;
if (isPull)
{
String2.gameObject.SetActive(true);
String1.SetPosition(0, TopPos);
String1.SetPosition(1, pos);
String2.SetPosition(0, pos);
String2.SetPosition(1, BottomPos);
}
else
{
String2.gameObject.SetActive(false);
String1.SetPosition(0, TopPos);
String1.SetPosition(1, BottomPos);
}
}
void Update()
{
Vector2 mousePos = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Input.GetMouseButtonDown(0))
{
startPos = mousePos;
isPull = true;
Arrow = Instantiate(ArrowPrefab);
SetArrowPos(Anchor.transform.position);
}
else if (Input.GetMouseButton(0))
{
Vector2 distance = Vector2.ClampMagnitude((mousePos - startPos), maxString);
Vector2 pos = (Vector2)Anchor.transform.position + distance;
StringRender(pos);
float angle = Mathf.Atan2(mousePos.y - startPos.y, mousePos.x - startPos.x);
transform.rotation = Quaternion.AngleAxis(angle * Mathf.Rad2Deg, Vector3.forward);
SetArrowPos(pos);
}
if (Input.GetMouseButtonUp(0))
{
Vector2 force = Vector2.ClampMagnitude((startPos - mousePos), maxString);
Arrow.ArrowShot(force * power);
isPull = false;
StringRender(Vector2.zero);
}
}
private void SetArrowPos(Vector2 pos)
{
Arrow.transform.position = pos;
Arrow.transform.rotation = this.transform.rotation;
}
}
引いた長さによって矢の速さが変わります。実行して下記のように矢を飛ばすことが出来ればOKです。

