今回は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です。