【Unity2D】追尾弾をつくる
正規化して、速度を3にした
— 相生葵 (@pirorirori_n712) 2018年10月21日
可愛いキャラクターは【Rド】様(https://t.co/80g5E20XwZ … …) pic.twitter.com/yn2kRJb9O0
※注意(10/23 追記)
この記事ではRigidBody2Dコンポネントのvelocityを使っていますが
Vector3.MoveTowardsを使う方法が一番簡単です。
使い方は以下の通りです。
gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, player.transform.position, distance);
gamebjectは弾、playerはプレイヤー、つまり目的地、ターゲットです。
このメソッドの3つ目の引数、distanceには距離が入るらしいです。
Time.deltaTimeが入れられていることが多いですが、私はまだよく分かっていないです。
これを使ってうごかしたものが以下です。
とてもきれいに動いてくれます。
Vector3.MoveTowards()
— 相生葵 (@pirorirori_n712) October 21, 2018
可愛いキャラクターは【Rド】様(https://t.co/80g5E20XwZ … … …) pic.twitter.com/ctqFBsG80x
以下は、velocityを使う本記事の内容です。
弾の移動はRigidBody2Dコンポネントのvelocityを使います。
使い方は以下です。
gameObject.GetComponent<RigidBody2D>().velocity=Vector2;
右辺の「Vector2」に適当なベクトルを入れると、
思った方向に動いてくれるのですが
方向については以下の記事で書いているので
こちらでは詳しくは触れません。
aoaoaoaoaoaoaoi.hatenablog.com
今回は、敵から自機に向かってくる追尾弾を作るので
「弾から自機に向かうベクトル」を何度も計算して
軌道を修正しながら移動させる必要があります。
ベクトルの向きは「弾から自機へのベクトル」です。
これは、「原点から自機へのベクトル」から「原点から弾へのベクトル」を引いて出します。
これを、Updateメソッドの中で常に計算してvelocityに入れれば、
弾は思った通り常にプレイヤーを追いかけてくれます。
しかし、一つ問題があります。
それは、速度です。
追尾弾
— 相生葵 (@pirorirori_n712) 2018年10月21日
単純にvelocityに値を入れると、プレイヤーに近づくにつれ速度が遅くなってしまう…
可愛いキャラクターは【Rド】様(https://t.co/80g5E20XwZ …) pic.twitter.com/d3nsKedGQi
単純にvelocityに求めたベクトルを入れただけでは、
弾の速度が変化していってしまいます。
ベクトルの向きは弾の飛んでいく向きを表します。
では、速度は何によって決まるのかというと
それはベクトルの長さです。
弾は時間がたつにつれ、プレイヤーに近づきます。
そのため、
弾からプレイヤーへと伸びるベクトルの長さは段々と小さくなっていき
速度が遅くなってしまうのです。
以下では、青い三角を自機、赤い丸を弾としています。
ここで、必要となってくるものが正規化です。
ベクトルの正規化とは、
向きをそのままに保ちながら、長さを1にすることです。
これは、Unityで「Vector3.normalized」が用意されています。
この正規化で一度ベクトルの長さを1にし、
任意の速度をかけることで
任意の一定の速度を保つことができます。
以下では、
ベクトルを正規化してから速度3をかけて
弾を3という一定の速度に保ちながらプレイヤーを追尾させています。
正規化して、速度を3にした
— 相生葵 (@pirorirori_n712) 2018年10月21日
可愛いキャラクターは【Rド】様(https://t.co/80g5E20XwZ … …) pic.twitter.com/yn2kRJb9O0
コード例
以上のことを踏まえて、書いたコードが以下です。
以下のスクリプトは敵につけています。
弾からプレイヤーへのベクトルをUpdateメソッド内で計算し直すために
リストに弾のプレハブを保存して使用しています。
またここでは、プレイヤーを永遠に追いかける弾をつくっていますが
実際のゲームに使う際は、
敵からプレイヤーへの追尾弾は回避できるものにしておく方がいいと思います。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class TamaToPlayerFollow : MonoBehaviour { //プレイヤー public GameObject player; //弾のプレハブ public GameObject tama; //弾を一秒ごとに打ち出す private float targetTime = 1.0f; private float currentTime = 0; //弾を保存しておくリスト private List<GameObject> list = new List<GameObject>(); // Update is called once per frame void Update() { //弾を一秒ごとに打ち出すためのもの currentTime += Time.deltaTime; if(targetTime < currentTime) { currentTime = 0; //敵の位置を保存 var pos = this.gameObject.transform.position ; //弾のプレハブを作成 var t = Instantiate(tama) as GameObject; //リストに弾を保存しておく list.Add(t); //弾の初期位置を敵の位置にする t.transform.position = pos; } //リストから一つずつ弾を取り出してベクトルの向きを修正する foreach (var l in list) { //弾のvelocityにベクトルを入れる //弾からプレイヤーへのベクトルを求めて、正規化し任意の速さ3をかける l.GetComponent<Rigidbody2D>().velocity = (player.transform.position - l.transform.position).normalized*3; } } }