注意
本記事で掲載されている動作の実装方法及びプログラムのソースコードは最適な方法ではない可能性があります。今後不具合等が判明した場合には修正及び改良をおこなう可能性があります。
また今後自分で同機能を実装する場合の参考にする可能性もあるためソースコードだけではなく説明しつつ記事を進めていきます。
Unityによる自作ゲーム開発進捗その30になります!
今回は制限時間と自軍の拠点数を画面上に表示するシステムを作成しました。
新しいスクリプトを1つ既存のスクリプトを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 TimerSystem m_timer_system;
[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 = 3;
private int m_center_state = 3;
private int m_right_state = 3;
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 < 4; 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;
m_timer_system.PlayerScoreUpdate();
if (m_left_state < 0) m_left_state = 0;
switch (m_left_state) {
case 2:
m_pop_point[0].MoveObject(new Vector3(50.0f, 2.5f, 90.0f));
break;
case 1:
m_pop_point[0].MoveObject(new Vector3(50.0f, 2.5f, 65.0f));
break;
case 0:
m_pop_point[0].MoveObject(new Vector3(50.0f, 2.5f, 40.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;
m_timer_system.PlayerScoreUpdate();
if (m_center_state < 0) m_center_state = 0;
switch (m_center_state) {
case 2:
m_pop_point[1].MoveObject(new Vector3(75.0f, 2.5f, 90.0f));
break;
case 1:
m_pop_point[1].MoveObject(new Vector3(75.0f, 2.5f, 65.0f));
break;
case 0:
m_pop_point[1].MoveObject(new Vector3(75.0f, 2.5f, 40.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;
m_timer_system.PlayerScoreUpdate();
if (m_right_state < 0) m_right_state = 0;
switch (m_right_state) {
case 2:
m_pop_point[2].MoveObject(new Vector3(110.0f, 2.5f, 90.0f));
break;
case 1:
m_pop_point[2].MoveObject(new Vector3(110.0f, 2.5f, 65.0f));
break;
case 0:
m_pop_point[2].MoveObject(new Vector3(110.0f, 2.5f, 40.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 戦闘エリア変更に伴ってモブの初期位置変更
2021-06-10 川の作成に伴ってモブの沸くポイントの高さ修正
2021-07-22 プレイヤー側の本拠地システムに対応
2021-08-06 拠点数を表示させるシステムに対応
[タスク]
(済)タスク1 プレイヤーキャラのステータスを反映させる
(済)タスク2 臨時防衛拠点数
タスク3 メニュー画面から各ラインのキャラクターを受け取るようにする
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class TimerSystem : MonoBehaviour{
private const float m_defense_time = 300.0f;
private const int m_player_base_count = 9;
private TextMeshProUGUI m_time_object;
private TextMeshProUGUI m_player_score;
private TextMeshProUGUI m_enemy_score;
private float m_time_count = 0.0f;
private float m_time_remain = 0.0f;
private int m_player_base;
public void PlayerScoreUpdate() {
m_player_base -= 1;
m_player_score.text = m_player_base.ToString();
}
private void Start() {
m_time_object = transform.GetChild(0).GetComponent<TextMeshProUGUI>();
m_player_score = transform.GetChild(1).GetComponent<TextMeshProUGUI>();
m_enemy_score = transform.GetChild(2).GetComponent<TextMeshProUGUI>();
m_time_remain = m_defense_time;
m_time_object.text = string.Format("{0:00}:{1:00}", (int)m_time_remain / 60, (int)m_time_remain % 60);
m_player_base = m_player_base_count;
m_player_score.text = m_player_base.ToString();
}
private void FixedUpdate() {
m_time_count += Time.deltaTime;
if(m_time_count >= 1.0f) {
m_time_remain -= m_time_count;
m_time_count = 0.0f;
print(m_time_remain % 60);
m_time_object.text = string.Format("{0:00}:{1:00}", (int)m_time_remain / 60, (int)m_time_remain % 60);
}
}
}
/*
[規則]
p_ 外部アクセス
m_ メンバー変数
l_ ローカル変数
a_ 引数
[説明]
[バージョン]
2021-08-06 時間制限システムの追加
[タスク]
*/
private void FixedUpdate() {
m_time_count += Time.deltaTime;
if(m_time_count >= 1.0f) {
m_time_remain -= m_time_count;
m_time_count = 0.0f;
print(m_time_remain % 60);
m_time_object.text = string.Format("{0:00}:{1:00}", (int)m_time_remain / 60, (int)m_time_remain % 60);
}
}
1秒間隔で残り時間の変数を更新するようにし、合計秒数を分で割って分を表示、秒数を分で割った余りを秒数としてテキストで表示するようにしています。
public void PlayerScoreUpdate() {
m_player_base -= 1;
m_player_score.text = m_player_base.ToString();
}
【m_player_base】には拠点数が入っており、拠点が壊されたタイミングでこの関数を呼び変数をデクリメントしています。