【unity備忘録13】アークタンジェント関数で敵に向かって飛ぶ弾を作る方法【unity2D】

アイキャッチ ゲーム制作
スポンサーリンク

こんにちは、slashです。
今回はunity2Dで敵へ向かって飛ぶ弾を作る方法です。

また、おまけで常に敵を追尾する追尾弾の作成もやってみます。


アークタンジェント関数

今回のポイントとなるのがアークタンジェント関数Mathf.Atan2です。

これはアークタンジェントの値を計算してくれます。これにより、オブジェクトが進むべき方向を求める事ができます。


下準備

今回は「自機」(Player)、「弾」(Bullet)、「敵」(Enemy)となるオブジェクトを用意します。

「自機」が「弾」を発射すると「敵」の位置をめがけて飛んでいく、という動作を作成していきます。

まずはグラフィックを用意してSceneに適当に配置します。

Player,Enemy,Bulletを配置


敵(Enemy)の設定

「敵」のオブジェクトはタグをEnemyにします。今回はこのタグで敵かどうかを判断するように作ります。

Enemyタグを設定

敵に弾がヒットしたかどうかの判定も行うので、BoxCollider2Dをアタッチして当たり判定を作り、IsTriggerにチェックを入れておきます。

また、今回は省略しますが、敵を動かしたい場合はC#スクリプトをアタッチして好みの動作を行うようにしておくと良いでしょう。


弾(Bullet)の設定

弾は丸い形のグラフィックなのでCircleCollider2Dをアタッチして当たり判定を作ります。

また、今回はRigidbody2Dの機能で弾の速度を設定するので、Rigidbody2Dもアタッチしておきます。

Bulletの設定

C#Scriptを新規で作成します。これをBulletControllerと名付けました。これを弾にアタッチします。スクリプト内容を以下に記載します。

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

public class BulletController : MonoBehaviour
{
    public float Speed = 5.0f;    
    Rigidbody2D rbody;

    GameObject EnemyObj;
    Vector2 BulletVector;

    // Start is called before the first frame update
    void Start()
    {
        rbody = GetComponent<Rigidbody2D>();
        FindEnemy();

        if (EnemyObj == null)
        {
            //敵がいない場合 弾を真上に飛ばす
            BulletVector = new Vector2(0.0f, Speed);
            rbody.velocity = BulletVector;
        }
        else
        {
            //敵がいる場合は弾を敵に向けて飛ばす
            SetBulletDireciton();
        }
        
    }

    void FixedUpdate()
    {        
        if ((Mathf.Abs(transform.position.x) > 4.0f) || (Mathf.Abs(transform.position.y) > 6.0f))
        {
            Destroy(gameObject);//弾が画面外へ飛び出したら消す
        }
    }

    void FindEnemy()
    {
        EnemyObj = GameObject.FindGameObjectWithTag("Enemy");//Enemyタグがついたオブジェクトを検索して取得
    }

    void SetBulletDireciton()
    {
        //弾の飛ぶ方向を設定するメソッド        
        if (EnemyObj != null)
        {
            //敵がいる場合 敵に向けて弾を飛ばす
            float angle = BulletAngle(EnemyObj);
            BulletVector = new Vector2(Speed * Mathf.Cos(angle), Speed * Mathf.Sin(angle));
        }
        
        rbody.velocity = BulletVector;

    }

    float BulletAngle(GameObject Obj)
    {
        //弾と目的のオブジェクトとの角度を返す
        float bulletX = transform.position.x;//このオブジェクトのx座標
        float bulletY = transform.position.y;//このオブジェクトのy座標
        float ObjX = Obj.transform.position.x;//目的のオブジェクトx座標
        float ObjY = Obj.transform.position.y;//目的のオブジェクトy座標
        float dX = ObjX - bulletX;
        float dY = ObjY - bulletY;
        float Angle = Mathf.Atan2(dY, dX);//目的オブジェクトとの角度計算        
        return Angle;
    }

    //弾が敵にヒットした時の処理
    void OnTriggerEnter2D(Collider2D collision)
    {
        Destroy(collision.gameObject);//敵を消す
        Destroy(gameObject);//敵にヒットしたら、このオブジェクトは消える
    }
}

このスクリプトは何をしているかというと、

GameObject.FindGameObjectWithTag(“Enemy”)で、Enemyタグがついたオブジェクトがいるかどうか検索

該当のオブジェクトがある場合はSetBulletDireciton()メソッドを実行して、敵へ向かう角度を計算して、その方向に弾を飛ばす。

という動作をさせています。また、敵に当たった場合は敵と弾が消えるようにしています。

BulletAngle内で、今回のポイントとなるアークタンジェント関数(Mathf.Atan2)を使って、弾を飛ばす角度を計算しています。

ここまで作ったら、弾(Bullet)をPrefab化しておきます。Prefab化したらSceneビューに残っている弾(Bullet)オブジェクトは削除しておきましょう。


自機(Player)

自機はただただ弾を発射するだけの砲台となってもらいます。

C#Scriptを新規で作成します。これをPlayerScriptと名付けました。これを自機にアタッチします。スクリプト内容は以下のような感じです。

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

public class PlayerScript : MonoBehaviour
{
    public GameObject Bulletprefab;

    void Update()
    {
        if (Input.GetMouseButtonDown(0)) 
        {
            //左クリックで弾を発射
            Instantiate(Bulletprefab, new Vector3(transform.position.x, transform.position.y, 0.0f), Quaternion.identity);
        }
    }
}

このスクリプトでやっている事は、画面内を左クリックするとBulletprefabオブジェクトを生成する、ただそれだけのものです。

この内容でスクリプトを保存したら、先ほどPrefab化したBulletをインスペクターでBulletprefabに設定します。これで、画面内を左クリックするたびに弾が発射されるようになります。

BulletをBulletPrefabにセット


実行してみる

ここでゲームを実行してみます。

左クリックすると、弾が敵に向かって飛んでいきますね。

ちなみに今回は省略しましたが、敵は左右往復移動するようにスクリプトを設定してあります。弾は生成された時点での敵の位置めがけて一直線に飛んでいくので、左右に動き回る敵には避けられてしまう事もありますね。

スポンサーリンク


弾に追尾性能を付ける

BulletControllerの内容を少し改造して弾に追尾性能を付与してみます。

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

public class BulletController : MonoBehaviour
{
    public float Speed = 5.0f;    
    Rigidbody2D rbody;

    GameObject EnemyObj;
    Vector2 BulletVector;

    // Start is called before the first frame update
    void Start()
    {
        rbody = GetComponent<Rigidbody2D>();
        FindEnemy();

        if (EnemyObj == null)
        {
            //敵がいない場合 弾を真上に飛ばす
            BulletVector = new Vector2(0.0f, Speed);
            rbody.velocity = BulletVector;
        }
        else
        {
            //敵がいる場合は弾を敵に向けて飛ばす
            SetBulletDireciton();
        }
        
    }

    void FixedUpdate()
    {        
        if (EnemyObj != null)
        {
            //敵がいる場合は常に敵を追尾し続ける
            SetBulletDireciton();
        }

        if ((Mathf.Abs(transform.position.x) > 4.0f) || (Mathf.Abs(transform.position.y) > 6.0f))
        {
            Destroy(gameObject);//弾が画面外へ飛び出したら消す
        }
    }

    void FindEnemy()
    {
        EnemyObj = GameObject.FindGameObjectWithTag("Enemy");//Enemyタグがついたオブジェクトを検索して取得
    }

    void SetBulletDireciton()
    {
        //弾の飛ぶ方向を設定するメソッド        
        if (EnemyObj != null)
        {
            //敵がいる場合 敵に向けて弾を飛ばす
            float angle = BulletAngle(EnemyObj);
            BulletVector = new Vector2(Speed * Mathf.Cos(angle), Speed * Mathf.Sin(angle));
        }
        
        rbody.velocity = BulletVector;

    }

    float BulletAngle(GameObject Obj)
    {
        //弾と目的のオブジェクトとの角度を返す
        float bulletX = transform.position.x;//このオブジェクトのx座標
        float bulletY = transform.position.y;//このオブジェクトのy座標
        float ObjX = Obj.transform.position.x;//目的のオブジェクトx座標
        float ObjY = Obj.transform.position.y;//目的のオブジェクトy座標
        float dX = ObjX - bulletX;
        float dY = ObjY - bulletY;
        float Angle = Mathf.Atan2(dY, dX);//目的オブジェクトとの角度計算        
        return Angle;
    }

    //弾が敵にヒットした時の処理
    void OnTriggerEnter2D(Collider2D collision)
    {
        Destroy(collision.gameObject);//敵を消す
        Destroy(gameObject);//敵にヒットしたら、このオブジェクトは消える
    }
}

変更点は、赤字の部分を追加した事だけです。

FixedUpdate内で常にSetBulletDireciton()を実行する事で、弾が常に敵のいる方向に向かう追尾弾となります。


もう一度実行してみる

ここでもう一度ゲームを実行してみます。

弾が左右往復する敵を追尾した結果、カーブを描くような軌道になっていますね。

コメント

タイトルとURLをコピーしました