今回はUnityで「弓で矢を飛ばす」のを実装してみます。マウスで弓を引き、離した時に矢を撃つ感じです。Part1では弓の弦を引っ張るのを実装していきます。
はじめに
Unityのヴァージョンは2022.3.14f1です。下記、2つの画像を利用していきます。私がInkscapeで簡単に作成したものです。


実装開始
ここから実際に作成していきます。
弓の弦を作成
まずは、弓の弦を作成していきます。弓の画像を画面にセットします。

弓の配下に「空オブジェクト」を追加して名前をstring1とし、LineRendrerを追加します。
LineRendererは下記のようにサイズ、Width、色、マテリアルを変更します。

下記のようにLineRendererで弓の弦を作成することが出来ます。

弦をスクリプトで実装
弓の配下に「空オブジェクト」を2つ追加して、位置を弓の上下に配置します。

string1の座標をリセットしておきます。

下記スクリプトを作成します。
using UnityEngine;
public class Bow : MonoBehaviour
{
[SerializeField] private GameObject Top;
[SerializeField] private GameObject Bottom;
[SerializeField] private LineRenderer String1;
void Start()
{
Vector2 TopPos = Top.transform.position;
Vector2 BottomPos = Bottom.transform.position;
String1.SetPosition(0, TopPos);
String1.SetPosition(1, BottomPos);
}
}
弓にスクリプトを追加して、パラメータをセットします。

実行して、弦が作成されたらOKです。
マウスで弓を引く
次にマウスで弓を引けるようにします。
まずは、string1をコピーしてstring2を作成、弦の真ん中の位置に空オブジェクトを追加します。

スクリプトを下記に変更します。
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;
private Vector2 startPos;
private bool isPull;
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;
}
else if (Input.GetMouseButton(0))
{
Vector2 distance = mousePos - startPos;
StringRender((Vector2)Anchor.transform.position + distance);
}
if (Input.GetMouseButtonUp(0))
{
isPull = false;
StringRender(Vector2.zero);
}
}
}
スクリプトの簡単な説明
StringRenderで弦を表示しています。弓を引いてないときはstring1だけでまっすぐな状態、弓を引いてるときはstring1とstring2で「>」の形にしています。
Update内では、マウスを左クリック時に基準となるマウス位置を取得、マウスクリックしたまま動かすと弦の位置を変更、マウスクリックを離した時に初期状態に戻す処理を行っています。
それぞれのパラメータをセットします。

実行して、下記のようにマウスで弓を引けたらOKです。

弦がどこまでも引けてしまうので制限をかけるのを、弓の角度を変えていきます。スクリプトを下記に変更します。startとStringRendererは変更がないので省略してあります。
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;
private Vector2 startPos;
private bool isPull;
private float maxString = 1.2f;
void Update()
{
Vector2 mousePos = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Input.GetMouseButtonDown(0))
{
startPos = mousePos;
isPull = true;
}
else if (Input.GetMouseButton(0))
{
Vector2 distance = Vector2.ClampMagnitude((mousePos - startPos), maxString);
StringRender((Vector2)Anchor.transform.position + distance);
float angle = Mathf.Atan2(mousePos.y - startPos.y, mousePos.x - startPos.x);
transform.rotation = Quaternion.AngleAxis(angle * Mathf.Rad2Deg, Vector3.forward);
}
if (Input.GetMouseButtonUp(0))
{
isPull = false;
StringRender(Vector2.zero);
}
}
}
実行してみて、下記のように引っ張る限界が出来て、弓の角度が変わればOKです。

Part1では弓の弦を引っ張るここまでとします。Part2では実際に矢を飛ばしていきます。