【自作ゲーム開発23】戦闘マップの作成ー前編(川)【Unity】


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

はじめに

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

今回から数回に分けて戦闘マップの見栄えに手を入れていきます。

前編では地面の準備をしつつ川を作成しました。

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

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

using System;
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 AutoController[] m_auto_script = new AutoController[6];

    [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 int[] m_character_position = new int[6];

    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_auto_script[m_character_position[4]].LineChange("Left", m_left_state); // タスク3
                } else {
                    m_attacker2_position = Number.Left;
                    m_auto_script[m_character_position[5]].LineChange("Left", m_left_state); // タスク3
                }
            break;

            case Number.Center:
                if (a_attacker == 1) {
                    m_attacker1_position = Number.Center;
                    m_auto_script[m_character_position[4]].LineChange("Center", m_center_state); // タスク3
                } else {
                    m_attacker2_position = Number.Center;
                    m_auto_script[m_character_position[5]].LineChange("Center", m_center_state); // タスク3
                }
            break;

            case Number.Right:
                if (a_attacker == 1) {
                    m_attacker1_position = Number.Right;
                    m_auto_script[m_character_position[4]].LineChange("Right", m_right_state); // タスク3
                } else {
                    m_attacker2_position = Number.Right;
                    m_auto_script[m_character_position[5]].LineChange("Right", m_right_state); // タスク3
                }
            break;
        }
    }

    public void Initialize(int[] a_number) {
        Array.Copy(a_number, m_character_position, m_character_position.Length);

        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, 2.0f, 10.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_auto_script[m_character_position[0]].Initialize("Center", 3); // タスク3
        m_auto_script[m_character_position[1]].Initialize("Left", 0); // タスク3
        m_auto_script[m_character_position[2]].Initialize("Center", 0); // タスク3
        m_auto_script[m_character_position[3]].Initialize("Right", 0); // タスク3
        m_auto_script[m_character_position[4]].Initialize("Center", 1); // タスク3
        m_auto_script[m_character_position[5]].Initialize("Center", 2); // タスク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_auto_script[m_character_position[1]].BaseChange(m_left_state); // タスク3
            if (m_attacker1_position == Number.Left) m_auto_script[m_character_position[4]].BaseChange(m_left_state); // タスク3
            if (m_attacker2_position == Number.Left) m_auto_script[m_character_position[5]].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_auto_script[m_character_position[2]].BaseChange(m_center_state); // タスク3
            if (m_attacker1_position == Number.Center) m_auto_script[m_character_position[4]].BaseChange(m_center_state); // タスク3
            if (m_attacker2_position == Number.Center) m_auto_script[m_character_position[5]].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_auto_script[m_character_position[3]].BaseChange(m_right_state); // タスク3
            if (m_attacker1_position == Number.Right) m_auto_script[m_character_position[4]].BaseChange(m_right_state); // タスク3
            if (m_attacker2_position == Number.Right) m_auto_script[m_character_position[5]].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 スタート関数を廃止してプレイヤーコントローラーから初期化を呼ぶように変更
    2021-06-04 メニュー画面からのキャラクター配置を戦闘画面へ反映させる
    2021-06-10 戦闘エリア変更に伴ってモブの初期位置変更

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

プログラムの変更点

var l_instance = Instantiate(m_mob_prefab, new Vector3(75.0f, 2.0f, 10.0f), Quaternion.Euler(0, 0, 0));

今回のプログラム変更点はモブの生成地点の変更のみとなります。

地形のコライダーの位置を変更した際生成位置と重なってしまい敵の位置がズレる現象が発生したためです。


戦闘マップの作成ー前編

今回の戦闘マップ作製は以下の点です。

  • 戦闘エリア外を緑系の地面テクスチャにする
  • Terrainの高さを調整して厚さを出す
  • 川用に溝を作る
  • 川のマテリアルを付けているオブジェクトで川を表現
  • 川沿いを岩のテクスチャにする

動画


記事のリンク

コメントを残す

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