【Unity】自機に向かってくる弾をつくる(2D)

弾幕STGでよくある自機に向かってくる弾をつくります(追尾弾ではありません)

※注意(10/21 追記)
この記事ではRigidBody2Dコンポネントのvelocityを使っていますが
Vector3.MoveTowardsを使う方法が一番簡単です。
使い方は以下の通りです。

gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, player.transform.position, distance);

gamebjectは弾、playerはプレイヤー、つまり目的地、ターゲットです。
このメソッドの3つ目の引数、distanceには距離が入るらしいです。
Time.deltaTimeが入れられていることが多いですが、私はまだよく分かっていないです。
以下、velocityを使う本記事の内容です。

前提

弾を動かす方法はRigidBody2Dコンポネントのvelocityを使います。 使い方は、

gameObject.GetComponent<RigidBody2D>().velocity=Vector2;

gameObjectはプレイヤーに向かって飛んでいく弾です。
弾の飛んでいく向きは右辺のVector2次第なので
Vector2に何の値を入れればいいかを考えていきます。
UnityのVector2について
ベクトルについて

考えるパート

目標:Vector2に適当な値(方向)を入れて、弾を「敵がいる位置からプレイヤーに向かって飛ばす」
ベクトルには方向と大きさがありますが、
方向は大きさが変わっても変わらないので
ここでは、ベクトルの大きさは考えません。
弾を敵からプレイヤーに向かって飛ばしたいということは、
ベクトルの向きは「敵の位置→プレイヤーの位置」となります。
青い丸を自機、赤い三角を敵とするとベクトルは以下のようになります。
f:id:aoaoaoaoaoaoaoi:20181014190842p:plain
このベクトルを求められれば、弾を自機に向かって飛ばすことができます。
まず今分かっているベクトルは
原点から「敵機へのベクトル」、
そして原点から「自機へのベクトル」です。
なぜこの二つのベクトルが分かっているかというと、
二つのgameObjectの位置は
gameObject.tranform.positionで取得することができるからです。
さらに、
なぜgameObject.tranform.positionで取得した座標で
原点からそれぞれ「敵」、「プレイヤー」へのベクトルが分かると言えるかというと
2つの点A(a1,a2),B(b1,b2)のベクトルは(b1-a1,b2-b2)で求められるからです。
原点の座標は(0,0)なので、
例えば敵の座標をgameObject.transform.positionで取得したときに(1,5)だった場合、
原点から敵へのベクトルは(1-0,5-0)となり、
そのまま敵の座標が「原点から敵へのベクトル」となります。
よって、
敵、プレイヤーともにgameObject.transform.positionで座標を取得できるので
どちらも既に原点からのベクトルが分かっていることになります。
f:id:aoaoaoaoaoaoaoi:20181014183602p:plain

それでは、この二つのベクトルを用いて
敵からプレイヤーに伸びているベクトルを求めます。
ここでは、ベクトルの引き算を使います。
ベクトルの引き算の定理は以下です。
ベクトルAベクトルBがあるとすると
ベクトルAベクトルBベクトルBの終点からベクトルAの終点に伸びるベクトル
f:id:aoaoaoaoaoaoaoi:20181014184402p:plain
ここから、
「原点から自機へのベクトル」から「原点から敵へのベクトル」を引けば
「敵から自機へのベクトル」を導きだすことができます。

コード例

(このスクリプトは敵につけています)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TamaToPlayer : MonoBehaviour {
    
    //プレイヤーオブジェクト
    public GameObject player;
    //弾のプレハブオブジェクト
    public GameObject tama;

    //一秒ごとに弾を発射するためのもの
    private float targetTime = 1.0f;
    private float currentTime = 0;
    
    // Update is called once per frame
    void Update () {
        //一秒経つごとに弾を発射する
        currentTime += Time.deltaTime;
        if (targetTime<currentTime) {
            currentTime = 0;
            //敵の座標を変数posに保存
            var pos = this.gameObject.transform.position;
            //弾のプレハブを作成
            var t = Instantiate(tama) as GameObject;
            //弾のプレハブの位置を敵の位置にする
            t.transform.position = pos;
            //敵からプレイヤーに向かうベクトルをつくる
            //プレイヤーの位置から敵の位置(弾の位置)を引く
            Vector2 vec = player.transform.position-pos;
            //弾のRigidBody2Dコンポネントのvelocityに先程求めたベクトルを入れて力を加える
            t.GetComponent<Rigidbody2D>().velocity= vec;
        }
    }
}

参考

点の座標を使ってベクトルの成分を表す
数学B ベクトル