【自作ゲーム開発21】ユーザー操作を従来のキャラクターに対応しました【Unity】


注意
本記事で掲載されている動作の実装方法及びプログラムのソースコードは最適な方法ではない可能性があります。
今後不具合等が判明した場合には修正及び改良をおこなう可能性があります。
また今後自分で同機能を実装する場合の参考にする可能性もあるためソースコードだけではなく説明しつつ記事を進めていきます。

はじめに

Unityによる自作ゲーム開発進捗その21になります!

今回はユーザー操作スクリプトを改良して一部の従来キャラクターも操作出来るようにしました。

既存のスクリプトを4つ新しいスクリプトを1つ更新します。

以下に動画でのコピー用にソースコードを掲載しています。

using Cinemachine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class PlayerController : MonoBehaviour{
    static class Number {
        public const int Left = 0;
        public const int Center = 1;
        public const int Right = 2;
    }

    /// <summary>
    /// 0-Hero 1-Mage 2-Dragoon 3-Knight 4-Bishop 5-Gunner
    /// </summary>
    [SerializeField]
    private GameObject[] m_character_list = new GameObject[6];

    private Rigidbody[] m_character_body = new Rigidbody[6];
    private NavMeshAgent[] m_character_navi = new NavMeshAgent[6];
    private Animator[] m_character_animation = new Animator[6];

    [SerializeField]
    private CharacterManager m_character_script;

    [SerializeField]
    private CinemachineVirtualCamera m_character_camera;

    private GameObject m_range_object;
    private RangeSystem m_range_system;

    private GameObject m_direction_object;
    private DirectionSystem m_direction_system;

    private Vector3 m_vector3;

    private Quaternion m_rotation = Quaternion.identity;

    private const float m_turn_speed = 20.0f;

    private float m_move_speed = 0.07f;
    private float m_horizontal = 0.0f;
    private float m_vertical = 0.0f;

    private int m_character_number = 5;

    private bool m_range_mode = false;
    private bool m_range_cancel = false;

    private bool m_direction_mode = false;
    private bool m_direction_cancel = false;

    enum STATE{
        MOVE,
        RANGE,
        DIRECTION
    }; STATE e_state;

    public void CharacterSetting(int a_number) {
        m_character_script.Initialize();

        // タスク7
        m_character_number = 5;
        m_character_list[0].transform.position = GameObject.Find("StartPositionL").transform.position;
        m_character_list[1].transform.position = GameObject.Find("StartPositionC").transform.position;
        m_character_list[2].transform.position = GameObject.Find("StartPositionR").transform.position;
        m_character_list[3].transform.position = GameObject.Find("StartPositionA1").transform.position;
        m_character_list[4].transform.position = GameObject.Find("StartPositionA2").transform.position;
        m_character_list[5].transform.position = GameObject.Find("StartPositionP").transform.position;

        m_character_camera.Follow = m_character_list[m_character_number].transform;
        m_character_navi[m_character_number].enabled = false;
        m_character_body[m_character_number].useGravity = true;
        m_character_body[m_character_number].isKinematic = false;
    }

    private void Start(){
        for(int l_loop = 0; l_loop < m_character_list.Length; l_loop += 1) {
            m_character_body[l_loop] = m_character_list[l_loop].GetComponent<Rigidbody>();
            m_character_navi[l_loop] = m_character_list[l_loop].GetComponent<NavMeshAgent>();
            m_character_animation[l_loop] = m_character_list[l_loop].GetComponent<Animator>();
        }

        CharacterSetting(5);

        m_direction_object = GameObject.Find("DirectionObject");
        m_direction_system = m_direction_object.GetComponent<DirectionSystem>();
        m_direction_system.DirectionSetting(false, this.transform);

        m_range_object = GameObject.Find("RangeObject");
        m_range_system = m_range_object.GetComponent<RangeSystem>();
        m_range_system.RangeSetting(false, this.transform.position, 0.0f);      
    }

    private void Update(){
        m_horizontal = Input.GetAxis("Horizontal"); // タスク2
        m_vertical = Input.GetAxis("Vertical"); // タスク2

        if ((Input.GetKeyDown("r")) && (!m_range_cancel) && (!m_direction_mode)) {
            m_range_mode = !m_range_mode;

            if (m_range_mode) {
                m_range_object.SetActive(m_range_mode);
                m_range_system.RangeSetting(m_range_mode, m_character_list[m_character_number].transform.position, 10.0f); // タスク3
                e_state = STATE.RANGE;
                m_character_animation[m_character_number].SetBool("animation_move", false);
            } else {
                m_range_cancel = true;    
            }
        }

        if ((Input.GetKeyDown("t")) && (m_range_mode)) m_range_system.TowerCreate(); // タスク4

        if ((Input.GetKeyDown("f")) && (!m_direction_cancel) && (!m_range_mode)) {
            m_direction_mode = !m_direction_mode;

            if (m_direction_mode) {
                m_direction_object.SetActive(m_direction_mode);
                m_direction_system.DirectionSetting(m_direction_mode, m_character_list[m_character_number].transform);
                e_state = STATE.DIRECTION;
                m_character_animation[m_character_number].SetBool("animation_move", false);
            } else {
                m_direction_cancel = true;
            }
        }

        if ((Input.GetKeyDown("g")) && (m_direction_mode)) m_direction_system.AttackStart(); // タスク5

        if (Input.GetKeyDown("1")) m_character_script.AttackerCommand(1, Number.Left); // タスク6
        if (Input.GetKeyDown("2")) m_character_script.AttackerCommand(1, Number.Center); // タスク6
        if (Input.GetKeyDown("3")) m_character_script.AttackerCommand(1, Number.Right); // タスク6

        if (Input.GetKeyDown("8")) m_character_script.AttackerCommand(2, Number.Left); // タスク6
        if (Input.GetKeyDown("9")) m_character_script.AttackerCommand(2, Number.Center); // タスク6
        if (Input.GetKeyDown("0")) m_character_script.AttackerCommand(2, Number.Right); // タスク6
    }

    private void FixedUpdate(){
        switch(e_state){
            case STATE.MOVE:
                m_vector3.Set(m_horizontal, 0f, m_vertical);
                m_vector3.Normalize();

                bool l_horizontal_input = !Mathf.Approximately (m_horizontal, 0f);
                bool l_vertical_input = !Mathf.Approximately (m_vertical, 0f);
                bool l_move = l_horizontal_input || l_vertical_input;
                m_character_animation[m_character_number].SetBool ("animation_move", l_move);

                Vector3 l_rotation = Vector3.RotateTowards (m_character_list[m_character_number].transform.forward, m_vector3, m_turn_speed * Time.deltaTime, 0f);
                m_rotation = Quaternion.LookRotation (l_rotation);

                m_character_body[m_character_number].MovePosition (m_character_body[m_character_number].position + m_vector3 * m_move_speed);
                m_character_body[m_character_number].MoveRotation (m_rotation); 
            break;

            case STATE.RANGE:
                if ((m_range_cancel) && (m_range_system.RangeSetting(false, m_character_list[m_character_number].transform.position, 0.0f))) {
                    m_range_cancel = false;
                    e_state = STATE.MOVE;
                }
            break;

            case STATE.DIRECTION:
                this.transform.rotation = m_direction_object.transform.rotation;

                if ((m_direction_cancel) && (m_direction_system.DirectionSetting(false, m_character_list[m_character_number].transform))) {
                    m_direction_cancel = false;
                    e_state = STATE.MOVE;
                }

                break;
        }

        m_horizontal = m_vertical = 0.0f;
    }

    public void PlayerSpeedSet(float a_speed){
        m_move_speed = a_speed; // タスク1
    }
}

/*
    [規則]
    p_ 外部アクセス
    m_ メンバー変数
    l_ ローカル変数
    a_ 引数
    e_ 列挙型

    [説明]

    [バージョン]
    2020-12-30 キーボードによるプレイヤーキャラの移動実装(回転無し)
    2021-01-09 プレイヤーキャラのモデルとアニメーション反映及び回転動作
    2021-04-23 座標指定モードへの切り替えとタワーの設置
    2021-04-30 攻撃向き指定モードへの切り替えと臨時エフェクトの発生
    2021-05-19 遊撃隊へのライン変更指示追加
    2021-05-28 全ての指揮官キャラクターを操作出来るように変更

    [タスク]
    タスク1 上限値の制限が必要
    タスク2 コントローラーによる動作も追加する
    タスク3 射程を制限する臨時半径
    タスク4 タワーの種類を渡す必要がある
    タスク5 攻撃の種類やステータスを渡すようにする
    タスク6 対応ボタンは臨時
    タスク7 メニューシーンから渡されたデータに変更する
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharacterManager : MonoBehaviour {
    static class Number {
        public const int Left = 0;
        public const int Center = 1;
        public const int Right = 2;
    }

    [SerializeField]
    private GameObject m_mob_prefab;

    [SerializeField]
    private HeroPlayer m_hero_script;

    [SerializeField]
    private MagePlayer m_mage_script;

    [SerializeField]
    private DragoonPlayer m_dragoon_script;

    [SerializeField]
    private KnightPlayer m_knight_script;

    [SerializeField]
    private BishopPlayer m_bishop_script;

    [SerializeField]
    private GunnerPlayer m_gunner_script;

    [SerializeField]
    private PopSystem[] m_pop_point = new PopSystem[3];

    private List<GameObject> m_mob_prefab_list = new List<GameObject>();
    private List<AssultEnemy> m_mob_prefab_script = new List<AssultEnemy>();

    private GameObject[] m_left_base = new GameObject[5];
    private GameObject[] m_center_base = new GameObject[5];
    private GameObject[] m_right_base = new GameObject[5];

    private float m_time_count = 0.0f;

    private int m_left_state = 2;
    private int m_center_state = 2;
    private int m_right_state = 2;
    private int m_attacker1_position = Number.Center;
    private int m_attacker2_position = Number.Center;

    private short m_mob_count = 0;

    public void AttackerCommand(int a_attacker, int a_position) {
        switch (a_position) {
            case Number.Left:
                if (a_attacker == 1) {
                    m_attacker1_position = Number.Left;
                    m_knight_script.LineChange("Left", m_left_state); // タスク3
                } else {
                    m_attacker2_position = Number.Left;
                    m_bishop_script.LineChange("Left", m_left_state); // タスク3
                }
            break;

            case Number.Center:
                if (a_attacker == 1) {
                    m_attacker1_position = Number.Center;
                    m_knight_script.LineChange("Center", m_center_state); // タスク3
                } else {
                    m_attacker2_position = Number.Center;
                    m_bishop_script.LineChange("Center", m_center_state); // タスク3
                }
            break;

            case Number.Right:
                if (a_attacker == 1) {
                    m_attacker1_position = Number.Right;
                    m_knight_script.LineChange("Right", m_right_state); // タスク3
                } else {
                    m_attacker2_position = Number.Right;
                    m_bishop_script.LineChange("Right", m_right_state); // タスク3
                }
            break;
        }
    }

    public void Initialize() {
        m_mob_count = 30;

        string l_line = "Left";

        for (int l_loop = 0; l_loop < m_mob_count; l_loop += 1) {
            if (l_loop == m_mob_count / 3) l_line = "Center";
            if (l_loop == m_mob_count - (m_mob_count / 3)) l_line = "Right";
            var l_instance = Instantiate(m_mob_prefab, new Vector3(75.0f, 0.0f, 65.0f), Quaternion.Euler(0, 0, 0));
            l_instance.SetActive(false);
            m_mob_prefab_list.Add(l_instance);
            m_mob_prefab_script.Add(l_instance.GetComponent<AssultEnemy>());
            m_mob_prefab_script[l_loop].Initialize(l_line);
        }

        for (int l_loop = 0; l_loop < 3; l_loop += 1) {
            // タスク2
            m_left_base[l_loop] = GameObject.Find(string.Format("LeftBase{0}", l_loop));
            m_center_base[l_loop] = GameObject.Find(string.Format("CenterBase{0}", l_loop));
            m_right_base[l_loop] = GameObject.Find(string.Format("RightBase{0}", l_loop));
        }

        m_hero_script.Initialize("Left"); // タスク3
        m_mage_script.Initialize("Center"); // タスク3
        m_dragoon_script.Initialize("Right"); // タスク3
        m_knight_script.Initialize("Center", 1); // タスク3
        m_bishop_script.Initialize("Center", 2); // タスク3
        m_gunner_script.Initialize("Center", 3); // タスク3
    }

    private void Update() {
        m_time_count += Time.deltaTime;

        if (m_time_count > 1.0f) {
            BaseCheck();
            ActiveObject();
        }
    }

    private void BaseCheck() {
        if (!m_left_base[m_left_state].activeSelf) {
            m_left_state -= 1;

            if (m_left_state < 0) m_left_state = 0;

            switch (m_left_state) {
                case 1:
                    m_pop_point[0].MoveObject(new Vector3(50.0f, 0.5f, 90.0f));
                    break;

                case 0:
                    m_pop_point[0].MoveObject(new Vector3(50.0f, 0.5f, 65.0f));
                    break;
            }

            for (int l_loop = 0; l_loop < m_mob_count / 3; l_loop += 1) {
                m_mob_prefab_script[l_loop].BaseChange(m_left_state);
            }

            m_hero_script.BaseChange(m_left_state); // タスク3
            if (m_attacker1_position == Number.Left) m_knight_script.BaseChange(m_left_state); // タスク3
            if (m_attacker2_position == Number.Left) m_bishop_script.BaseChange(m_left_state); // タスク3
        }

        if (!m_center_base[m_center_state].activeSelf) {
            m_center_state -= 1;

            if (m_center_state < 0) m_center_state = 0;

            switch (m_center_state) {
                case 1:
                    m_pop_point[1].MoveObject(new Vector3(75.0f, 0.5f, 90.0f));
                    break;

                case 0:
                    m_pop_point[1].MoveObject(new Vector3(75.0f, 0.5f, 65.0f));
                    break;
            }

            for (int l_loop = m_mob_count / 3; l_loop < m_mob_count - (m_mob_count / 3); l_loop += 1) {
                m_mob_prefab_script[l_loop].BaseChange(m_center_state);
            }

            m_mage_script.BaseChange(m_center_state); // タスク3
            if (m_attacker1_position == Number.Center) m_knight_script.BaseChange(m_center_state); // タスク3
            if (m_attacker2_position == Number.Center) m_bishop_script.BaseChange(m_center_state); // タスク3
        }

        if (!m_right_base[m_right_state].activeSelf) {
            m_right_state -= 1;

            if (m_right_state < 0) m_right_state = 0;

            switch (m_right_state) {
                case 1:
                    m_pop_point[2].MoveObject(new Vector3(110.0f, 0.5f, 90.0f));
                    break;

                case 0:
                    m_pop_point[2].MoveObject(new Vector3(110.0f, 0.5f, 65.0f));
                    break;
            }

            for (int l_loop = m_mob_count - (m_mob_count / 3); l_loop < m_mob_count; l_loop += 1) {
                m_mob_prefab_script[l_loop].BaseChange(m_right_state);
            }

            m_dragoon_script.BaseChange(m_right_state); // タスク3
            if (m_attacker1_position == Number.Right) m_knight_script.BaseChange(m_right_state); // タスク3
            if (m_attacker2_position == Number.Right) m_bishop_script.BaseChange(m_right_state); // タスク3
        }
    }

    private void ActiveObject() {
        m_time_count = 0.0f;

        for (int l_loop = 0; l_loop < m_mob_count / 3; l_loop += 1) {
            if (m_mob_prefab_list[l_loop].activeSelf == false) {
                m_mob_prefab_list[l_loop].SetActive(true);
                m_mob_prefab_script[l_loop].MobState(true);
                break;
            }
        }

        for (int l_loop = m_mob_count / 3; l_loop < m_mob_count - (m_mob_count / 3); l_loop += 1) {
            if (m_mob_prefab_list[l_loop].activeSelf == false) {
                m_mob_prefab_list[l_loop].SetActive(true);
                m_mob_prefab_script[l_loop].MobState(true);
                break;
            }
        }

        for (int l_loop = m_mob_count - (m_mob_count / 3); l_loop < m_mob_count; l_loop += 1) {
            if (m_mob_prefab_list[l_loop].activeSelf == false) {
                m_mob_prefab_list[l_loop].SetActive(true);
                m_mob_prefab_script[l_loop].MobState(true);
                break;
            }
        }
    }
}

/*
    [規則]
    p_ 外部アクセス
    m_ メンバー変数
    l_ ローカル変数
    a_ 引数

    [説明]

    [バージョン]
    2020-12-12 指定数生成及びプーリング呼び出し
    2021-03-12 管理拠点を配列化し拠点管理を行いモブに伝える
    2021-03-17 センターライン指揮官キャラの生成と名前変更(旧CenterMobManagerEnemy)
    2021-03-25 戦闘ラインを1から3ラインに変更
    2021-04-05 敵キャラクター生成位置を真ん中へ(左下では生成時にナビエリアが遠くエラーが出る)
    2021-05-19 プレイヤーからのライン変更指示を遊撃キャラクターに反映させる
    2021-05-28 スタート関数を廃止してプレイヤーコントローラーから初期化を呼ぶように変更

    [タスク]
    (済)タスク1 プレイヤーキャラのステータスを反映させる
    (済)タスク2 臨時防衛拠点数
    タスク3 メニュー画面から各ラインのキャラクターを受け取るようにする
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class KnightPlayer : MonoBehaviour {
    [SerializeField]
    private GameObject m_defense_player;

    private List<GameObject> m_defense_prefab_list = new List<GameObject>();
    private List<DefensePlayer> m_defense_prefab_script = new List<DefensePlayer>();

    private Transform[] m_serch_object = new Transform[5];

    private NavMeshAgent m_navmesh_agent;
    private Animator m_animator;

    private int m_base_state = 2;
    private int m_attacker = 0;

    enum STATE {
        SET,
        SERCH,
    }; STATE e_state;

    public void BaseChange(int a_number) {
        m_base_state = a_number;

        if(m_attacker == 0) {
            for (int l_loop = 0; l_loop < 3; l_loop += 1) {
                m_defense_prefab_script[l_loop].BaseChange(m_base_state);
            }
        }

        m_navmesh_agent.SetDestination(m_serch_object[m_base_state].transform.position);
        m_animator.SetBool("animation_move", true);
        e_state = STATE.SET;
    }

    public void LineChange(string a_line, int a_number) {
        m_base_state = a_number;

        for (int l_loop = 0; l_loop <= a_number; l_loop += 1) {
            GameObject l_object = GameObject.Find(string.Format("{0}Base{1}", a_line, l_loop));
            m_serch_object[l_loop] = l_object.transform.Find(string.Format("SetPositionA{0}", m_attacker));
        }

        m_navmesh_agent.SetDestination(m_serch_object[m_base_state].transform.position);
        m_animator.SetBool("animation_move", true);
        e_state = STATE.SET;
    }

    public void Initialize(string a_line, int a_attacker) {
        m_navmesh_agent = GetComponent<NavMeshAgent>();
        m_animator = GetComponent<Animator>();
        m_attacker = a_attacker;

        if (m_attacker == 3) return;

        if (m_attacker == 0) {
            for (int l_loop = 0; l_loop < 3; l_loop += 1) {
                var l_instance = Instantiate(m_defense_player, this.transform);
                m_defense_prefab_list.Add(l_instance);
                m_defense_prefab_script.Add(l_instance.GetComponent<DefensePlayer>());
                m_defense_prefab_script[l_loop].Initialize(a_line, l_loop);
            }
        }

        for (int l_loop = 0; l_loop < 3; l_loop += 1) {
            GameObject l_object = GameObject.Find(string.Format("{0}Base{1}", a_line, l_loop));

            if (m_attacker == 0) {
                m_serch_object[l_loop] = l_object.transform.Find("SetPositionL");
            } else {
                m_serch_object[l_loop] = l_object.transform.Find(string.Format("SetPositionA{0}", m_attacker));
            }
        }

        m_navmesh_agent.SetDestination(m_serch_object[m_base_state].transform.position);
        m_animator.SetBool("animation_move", true);
    }

    private void FixedUpdate() {
        switch (e_state) {
            case STATE.SET:
                if (m_attacker == 3) return;

                if ((this.transform.position - m_serch_object[m_base_state].transform.position).sqrMagnitude < 1.0f) {
                    m_animator.SetBool("animation_move", false);
                    e_state = STATE.SERCH;
                }
                break;

            case STATE.SERCH:

                break;
        }
    }
}

/*
    [規則]
    p_ 外部アクセス
    m_ メンバー変数
    l_ ローカル変数
    a_ 引数

    [説明]

    [バージョン]
    2021-05-19 指揮官基本動作に加えて指示によるライン変更
    2021-05-28 ユーザー操作に対応

    [タスク]
    
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class BishopPlayer : MonoBehaviour {
    [SerializeField]
    private GameObject m_defense_player;

    private List<GameObject> m_defense_prefab_list = new List<GameObject>();
    private List<DefensePlayer> m_defense_prefab_script = new List<DefensePlayer>();

    private Transform[] m_serch_object = new Transform[5];

    private NavMeshAgent m_navmesh_agent;
    private Animator m_animator;

    private int m_base_state = 2;
    private int m_attacker = 0;

    enum STATE {
        SET,
        SERCH,
    }; STATE e_state;

    public void BaseChange(int a_number) {
        m_base_state = a_number;

        if (m_attacker == 0) {
            for (int l_loop = 0; l_loop < 3; l_loop += 1) {
                m_defense_prefab_script[l_loop].BaseChange(m_base_state);
            }
        }

        m_navmesh_agent.SetDestination(m_serch_object[m_base_state].transform.position);
        m_animator.SetBool("animation_move", true);
        e_state = STATE.SET;
    }

    public void LineChange(string a_line, int a_number) {
        m_base_state = a_number;

        for (int l_loop = 0; l_loop <= a_number; l_loop += 1) {
            GameObject l_object = GameObject.Find(string.Format("{0}Base{1}", a_line, l_loop));
            m_serch_object[l_loop] = l_object.transform.Find(string.Format("SetPositionA{0}", m_attacker));
        }

        m_navmesh_agent.SetDestination(m_serch_object[m_base_state].transform.position);
        m_animator.SetBool("animation_move", true);
        e_state = STATE.SET;
    }

    public void Initialize(string a_line, int a_attacker) {
        m_navmesh_agent = GetComponent<NavMeshAgent>();
        m_animator = GetComponent<Animator>();
        m_attacker = a_attacker;

        if (m_attacker == 3) return;

        if (m_attacker == 0) {
            for (int l_loop = 0; l_loop < 3; l_loop += 1) {
                var l_instance = Instantiate(m_defense_player, this.transform);
                m_defense_prefab_list.Add(l_instance);
                m_defense_prefab_script.Add(l_instance.GetComponent<DefensePlayer>());
                m_defense_prefab_script[l_loop].Initialize(a_line, l_loop);
            }
        }

        for (int l_loop = 0; l_loop < 3; l_loop += 1) {
            GameObject l_object = GameObject.Find(string.Format("{0}Base{1}", a_line, l_loop));

            if (m_attacker == 0) {
                m_serch_object[l_loop] = l_object.transform.Find("SetPositionL");
            } else {
                m_serch_object[l_loop] = l_object.transform.Find(string.Format("SetPositionA{0}", m_attacker));
            }
        }

        m_navmesh_agent.SetDestination(m_serch_object[m_base_state].transform.position);
        m_animator.SetBool("animation_move", true);
    }

    private void FixedUpdate() {
        switch (e_state) {
            case STATE.SET:
                if (m_attacker == 3) return;

                if ((this.transform.position - m_serch_object[m_base_state].transform.position).sqrMagnitude < 1.0f) {
                    m_animator.SetBool("animation_move", false);
                    e_state = STATE.SERCH;
                }
                break;

            case STATE.SERCH:

                break;
        }
    }
}

/*
    [規則]
    p_ 外部アクセス
    m_ メンバー変数
    l_ ローカル変数
    a_ 引数

    [説明]

    [バージョン]
    2021-05-19 指揮官基本動作に加えて指示によるライン変更
    2021-05-28 ユーザー操作に対応

    [タスク]
    
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class GunnerPlayer : MonoBehaviour {
    [SerializeField]
    private GameObject m_defense_player;

    private List<GameObject> m_defense_prefab_list = new List<GameObject>();
    private List<DefensePlayer> m_defense_prefab_script = new List<DefensePlayer>();

    private Transform[] m_serch_object = new Transform[5];

    private NavMeshAgent m_navmesh_agent;
    private Animator m_animator;

    private int m_base_state = 2;
    private int m_attacker = 0;

    enum STATE {
        SET,
        SERCH,
    }; STATE e_state;

    public void BaseChange(int a_number) {
        m_base_state = a_number;

        if (m_attacker == 0) {
            for (int l_loop = 0; l_loop < 3; l_loop += 1) {
                m_defense_prefab_script[l_loop].BaseChange(m_base_state);
            }
        }

        m_navmesh_agent.SetDestination(m_serch_object[m_base_state].transform.position);
        m_animator.SetBool("animation_move", true);
        e_state = STATE.SET;
    }

    public void LineChange(string a_line, int a_number) {
        m_base_state = a_number;

        for (int l_loop = 0; l_loop <= a_number; l_loop += 1) {
            GameObject l_object = GameObject.Find(string.Format("{0}Base{1}", a_line, l_loop));
            m_serch_object[l_loop] = l_object.transform.Find(string.Format("SetPositionA{0}", m_attacker));
        }

        m_navmesh_agent.SetDestination(m_serch_object[m_base_state].transform.position);
        m_animator.SetBool("animation_move", true);
        e_state = STATE.SET;
    }

    public void Initialize(string a_line, int a_attacker) {
        m_navmesh_agent = GetComponent<NavMeshAgent>();
        m_animator = GetComponent<Animator>();
        m_attacker = a_attacker;

        if(m_attacker == 3) return;

        if (m_attacker == 0) {
            for (int l_loop = 0; l_loop < 3; l_loop += 1) {
                var l_instance = Instantiate(m_defense_player, this.transform);
                m_defense_prefab_list.Add(l_instance);
                m_defense_prefab_script.Add(l_instance.GetComponent<DefensePlayer>());
                m_defense_prefab_script[l_loop].Initialize(a_line, l_loop);
            }
        }

        for (int l_loop = 0; l_loop < 3; l_loop += 1) {
            GameObject l_object = GameObject.Find(string.Format("{0}Base{1}", a_line, l_loop));

            if (m_attacker == 0) {
                m_serch_object[l_loop] = l_object.transform.Find("SetPositionL");
            } else {
                m_serch_object[l_loop] = l_object.transform.Find(string.Format("SetPositionA{0}", m_attacker));
            }
        }

        m_navmesh_agent.SetDestination(m_serch_object[m_base_state].transform.position);
        m_animator.SetBool("animation_move", true);
    }

    private void FixedUpdate() {
        switch (e_state) {
            case STATE.SET:
                if (m_attacker == 3) break;

                if ((this.transform.position - m_serch_object[m_base_state].transform.position).sqrMagnitude < 1.0f) {
                    m_animator.SetBool("animation_move", false);
                    e_state = STATE.SERCH;
                }
                break;

            case STATE.SERCH:

                break;
        }
    }
}

/*
    [規則]
    p_ 外部アクセス
    m_ メンバー変数
    l_ ローカル変数
    a_ 引数

    [説明]

    [バージョン]
    2021-05-28 既存のキャラクター動作に加えてユーザー操作に対応

    [タスク]
    
*/

ユーザー操作の変更

[SerializeField]
private GameObject[] m_character_list = new GameObject[6];

private Rigidbody[] m_character_body = new Rigidbody[6];
private NavMeshAgent[] m_character_navi = new NavMeshAgent[6];
private Animator[] m_character_animation = new Animator[6];

従来はテスト用キャラクターにスクリプトをアタッチし移動用のコンポーネント等を取得するようにしていましたが、今回から全ての操作キャラクター自体やコンポーネントを配列に取得するようにし、配列番号で操作キャラクターを選択するようにしました。


m_character_camera.Follow = m_character_list[m_character_number].transform;
m_character_navi[m_character_number].enabled = false;
m_character_body[m_character_number].useGravity = true;
m_character_body[m_character_number].isKinematic = false;

操作キャラクターは【NavMeshAgent】を停止したり物理演算を起動したりするのと同時にカメラを操作キャラクターにセットするようにしています。

public void Initialize(string a_line, int a_attacker) {
    m_navmesh_agent = GetComponent<NavMeshAgent>();
    m_animator = GetComponent<Animator>();
    m_attacker = a_attacker;

    if(m_attacker == 3) return;

    if (m_attacker == 0) {
        for (int l_loop = 0; l_loop < 3; l_loop += 1) {
            var l_instance = Instantiate(m_defense_player, this.transform);
            m_defense_prefab_list.Add(l_instance);
            m_defense_prefab_script.Add(l_instance.GetComponent<DefensePlayer>());
            m_defense_prefab_script[l_loop].Initialize(a_line, l_loop);
        }
    }

    for (int l_loop = 0; l_loop < 3; l_loop += 1) {
        GameObject l_object = GameObject.Find(string.Format("{0}Base{1}", a_line, l_loop));

        if (m_attacker == 0) {
            m_serch_object[l_loop] = l_object.transform.Find("SetPositionL");
        } else {
            m_serch_object[l_loop] = l_object.transform.Find(string.Format("SetPositionA{0}", m_attacker));
        }
    }

    m_navmesh_agent.SetDestination(m_serch_object[m_base_state].transform.position);
    m_animator.SetBool("animation_move", true);
}

各キャラクターは共通の初期化動作で引数【a_attacker】によりレーンを防衛するタイプ遊撃部隊操作キャラクターに分岐させるようにしています。


今回使用するアセット


動画


記事のリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です