55
1
0

第6回 - 敵の動作を実装する・カメラがプレイヤーを追従するようにする【Unity講座2022】

Published at October 11, 2022 10:41 p.m.
Edited at April 19, 2023 2:21 p.m.

敵の動作を実装する・カメラがプレイヤーを追従するようにする

今回の目標

  1. 敵の動作を実装する(続きから)
  2. カメラがプレイヤーを追従するようにする

1. 敵の動作を実装する(続きから)

1-1. 壁に衝突したときに進む方向を変える処理を実装する

前回の続きです。

1-1-1. 壁に衝突したことを検知するための処理を実装してみよう

  1. C#ファイルを作成する
    Assets / Scriptに「EnemyTrigger」というC#ファイルを作成します。
    作成したら開いてください。

  2. 余計なプログラムを削除する
    Start関数とUpdate関数を削除してください。

  3. 衝突と判定する関数を実装する
    壁との衝突判定を実装します。
    2Dでの衝突判定はOnTrigger2D関数を使用します。関数には引数(Collider2D col)があります。この引数には、触れたオブジェクトの情報が入ります。(※OnTrigger2Dが充てられているAがBに触れた時は引数にBの情報が入ります)

    OnTriggerEnter2D

    isTriggerがtrueのオブジェクトが触れた時に実行される

    OnTriggerStay2D

    isTriggerがtrueのオブジェクトが触れている間ずっと実行される

    OnTriggerExit2D

    isTriggerがtrueのオブジェクトが離れた時に実行される

    プログラムの内容

    それぞれのOnTrigger2D関数が実行された際に、触れた(or 離れた)オブジェクトが地面かどうかの判定を行い、地面だった場合は、地面に触れた(or 触れ続けている or 離れた)ことを変数に記録する。
    それらを元に現在どの状態(地面に触れているか否か)を返す関数(IsGround())を実装。この関数は、地面に触れた又は触れ続けている場合はtrue、離れた場合はfalseを返すような処理になっています。

    衝突判定プログラム(クリックして見る)
    csharp
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class EnemyTrigger : MonoBehaviour
    {
    
        private bool isGround = false;
        private bool isGroundEnter, isGroundStay, isGroundExit;
    
        /// <summary>
        /// 地面に触れているかどうかをチェックし、そのフラグを返す
        /// </summary>
        public bool IsGround() {
            if(isGroundEnter || isGroundStay) {
                isGround = true;
            } else if(isGroundExit) {
                isGround = false;
            }
    
            isGroundEnter = false;
            isGroundStay = false;
            isGroundExit = false;
    
            return isGround;
        }
    
        private void OnTriggerEnter2D (Collider2D col) {
            if (col.gameObject.CompareTag("Ground")) {
                isGroundEnter = true;
            }
        }
    
        private void OnTriggerStay2D (Collider2D col) {
            if (col.gameObject.CompareTag("Ground")) {
                isGroundStay = true;
            }
        }
    
        private void OnTriggerExit2D (Collider2D col) {
            if (col.gameObject.CompareTag("Ground")) {
                isGroundExit = true;
            }
        }
    }
    

1-1-2. 右腕と左腕にEnemyTriggerを充てる

題目の通り、「ArmLeft」と「ArmRight」に作成したEnemyTriggerを充てます。
EnemySkeletonプレハブを開き、両腕にEnemyTrigger.csをドラッグアンドドロップします。

image2

1-1-3. 実践:EnemyControllerで壁に衝突したときに向きを変える処理を実装してみよう

EnemyTrigger.cs で衝突を検知できるようになったので、壁に衝突したときに身体の向きと進行方向を変える処理を実装してみましょう!

条件

この処理はEnemyController.csに実装してください

ヒント

    - 処理の流れ -
  1. 両腕のオブジェクトを取得
  2. オブジェクトに充てられているEnemyTrigger.csを取得
  3. 毎フレーム:敵が衝突したかどうかのフラグ(isGrondで取得可能)をEnemyController.cs内で取得
  4. 毎フレーム:もし衝突したら進行方向を変える(MoveLeft() or MoveRight() を実行する)
解答:衝突したときに向きを変えるプログラム(クリックして見る)
csharp
/// EnemyController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyController : MonoBehaviour
{

    Vector2 position;

    SpriteRenderer spriteRenderer;

    GameObject leg;
    GameObject armLeft;
    GameObject armRight;

    private bool isMoveLeft = true;

    private float moveSpeed = 0.05f;


    void Start()
    {
        /// 両腕のオブジェクト情報を、オブジェクトに充てられたタグを元に取得
        armLeft = transform.Find("ArmLeft").gameObject;
        armRight = transform.Find("ArmRight").gameObject;

        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    void Update()
    {
        position = transform.position;

        /// 左腕が地面に当たった場合、左に進むフラグを立てる
        if (armLeft.GetComponent<EnemyTrigger_05th>().IsGround()) {
            isMoveLeft = true;

        /// 右腕が地面に当たった場合、左に進むフラグを折る
        } else if (armRight.GetComponent<EnemyTrigger_05th>().IsGround()) {
            isMoveLeft = false;
        }

        /// 左に進むフラグが立っている場合、左に進む
        if (isMoveLeft) {
            MoveLeft();

        /// 左に進むフラグが折れている場合、右に進む
        } else {
            MoveRight();
        }
    }

    void OnCollisionEnter2D(Collision2D col)
    {
        if(col.gameObject.CompareTag("Player")) {
            Destroy(gameObject);
        }
    }

    /// <summary>
    /// 左方向移動 関数
    /// </summary>
    private void MoveLeft () {
        position.x -= moveSpeed;

        spriteRenderer.flipX = true;
        transform.position = position;
    }

    /// <summary>
    /// 右方向移動 関数
    /// </summary>
    private void MoveRight () {
        position.x += moveSpeed;

        spriteRenderer.flipX = false;
        transform.position = position;
    }
}

2. カメラがプレイヤーを追従するようにする

カメラがキャラクターを追従する方法は様々あるのですが、今回はプレイヤーのX座標のみを追従するプログラムを実装してみます。

2-1. C#ファイルを作成する

Assets / Scriptに「CameraController」というC#ファイルを作成します。
作成したら開いてください。

2-2. CameraControllerをMain Cameraに充てる

作成したCameraController.csファイルをMain Cameraオブジェクトにドラッグアンドドロップしてください

2-3. プレイヤーを追従するプログラムの実装

CameraController.csにキャラクターを追従するようにするプログラムを実装していきます。

処理の流れ

  1. 追従対象オブジェクトを入れる変数を定義
  2. ゲーム開始時のカメラの座標を取得し保存
  3. 毎フレーム:追従対象オブジェクトのX座標を取得し保存
  4. 毎フレーム:保存した追従対象オブジェクトのX座標の値を、カメラのX座標に反映させる
  1. 追従対象オブジェクトを入れる変数を定義
    変数を定義する際に、型の前にpublicを付けることでUnityエディター上で変数に代入する値を指定することができます。
    このように書いてみましょう。

    csharp
    ///<summary>
    /// 追従対象のゲームオブジェクト
    /// <para>※ 基本的にはPlayer</para>
    ///</summary>
    public GameObject target;
    

    保存後、Unityエディターに戻りMain CameraのInspectorを見てみると、CameraController内にTargetという項目が追加されているはずです。
    image

    その項目にPlayerオブジェクトをドラッグアンドドロップしてください。そうすることで target 変数にPlayerオブジェクトを代入することができました。

  2. ゲーム開始時のカメラの座標を取得し保存
    transform.positionにはこのプログラムを充てているMain Cameraオブジェクトの座標が代入されています。
    今回はX座標のみを変更したいため、Y座標やZ座標は初期値のままにしなければいけません。そのため、ゲーム開始時の座標を保存しています。

    csharp
    /// <summary>
    /// このスクリプトを充てているオブジェクトの初期座標
    /// </summary>
    private Vector3 position;
    
    void Start()
    {
        /// ゲームスタート時のカメラの座標を記録
        position = transform.position;
    }
    
  3. 毎フレーム:追従対象オブジェクトのX座標を取得し保存
    このように書くことでターゲット(プレイヤー)のX座標を取得します。

    csharp
    /// <summary>
    /// 追従対象のX座標
    /// </summary>
    private float targetPositionX;
    
    void Update()
    {
        /// targetPositionXに追従対象のX座標を代入
        targetPositionX = target.GetComponent<Transform>().position.x;
    }
    
  4. 毎フレーム:保存した追従対象オブジェクトのX座標の値を、カメラのX座標に反映させる
    transform.positionの値を変更することでカメラの座標を変更することができます。
    transform.positionは Vector3型 なので、以下のように新しいインスタンスを作成し、X座標のみを追従対象のX座標の値にすることで、カメラのX座標をプレイヤーと同じ値にすることができます。

    csharp
    void Update()
    {
        /// 3に追記する
        /// このスクリプトを充てているオブジェクトのX座標のみを追従対象のX座標にする
        transform.position = new Vector3(targetPositionX, position.y, position.z);
    }
    

これでゲームを実行するとカメラがプレイヤーを追従するようになりました!

カメラがプレイヤーを追従するプログラム(クリックして見る)
csharp
/// CameraController.cs

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

public class CameraController : MonoBehaviour
{

    ///<summary>
    /// 追従対象のゲームオブジェクト
    /// <para>※ 基本的にはPlayer</para>
    ///</summary>
    public GameObject target;

    /// <summary>
    /// 追従対象のX座標
    /// </summary>
    private float targetPositionX;

        /// <summary>
        /// このスクリプトを充てているオブジェクトの初期座標
        /// </summary>
        private Vector3 position;

    void Start()
    {
        /// ゲームスタート時のカメラの座標を記録
        position = transform.position;
    }

    void Update()
    {
        /// targetPositionXに追従対象のX座標を代入
        targetPositionX = target.GetComponent<Transform>().position.x;

        /// このスクリプトを充てているオブジェクトのX座標のみを追従対象のX座標にする
        transform.position = new Vector3(targetPositionX, position.y, position.z);
    }
}

次回

  • HPや敵を倒したときのスコアを実装する
  • UIを作る

第7回 - HPとスコアを実装する!【Unity講座2022】
https://inct-densan.kibe.la/shared/entries/ab7928e4-0eb5-47ed-9bd1-b8f6721b769c