現場レベルのゲーム制作が、すべてここで学べます。
この講座は3Dダンジョン探索型RPGの作り方について説明しています。今回はその第6回目になります。
前回は戦闘シーンに敵キャラクターやプレイヤーパーティーのデータクラスを構築し、Scriptable Objectを用いてステータス管理を行う方法を学びました。
また、キャラクター表示システムも完了し、本格的なアクティブタイムバトルシステムの実装に取り掛かってきました。
前回の記事:

今回は通常攻撃のコマンドやスキルを実装し、相手のHPを削ることができる状態を目標に開発を進めていきます。単体攻撃だけではなく全体攻撃やランダム攻撃、前衛に当たりやすい攻撃など多種多様な設定を含めていきます。
キャラクタースキル実装
戦闘中にアクター・エネミーがとる行動は基本的にスキルとして実装します。スキルには攻撃するものや状態異常を付与するもの、回復するものなど様々な効果があります。
そしてそれらの効果にも共通の機能をもつものがあります。
例えばアクターの攻撃スキルは「エネミーにダメージを与える効果」を共通で持ちます。そのダメージの大きさはスキルによって異なるでしょうが、アクターの攻撃力や魔法攻撃力を参照してダメージを計算し、エネミーのHPを減少させる処理は同じものが使えます。
各スキルの名前や効果などのデータ作成はScriptableObjectにて行うことにします。
そのスキルデータのInspectorでの設定において、どのような効果をどれくらいの効果量で発揮できるかを指定できる状態を目標に実装していきましょう。
また一部のスキルは「エネミーにダメージを与えつつ、確率で毒状態を付与する」のように複数の効果を同時に設定できるようにしたいです。これもエディタ拡張を活かすことで機能として実現します。
多様なスキルの作り込みは講座の後半で行います。当面はカウントタイムバトルの実現のために最低限必要になる通常攻撃スキルのみを作っていきます。
ダメージ計算なども行わず、固定の数値を相手のHPから減らすような内容にします。
スキル効果クラス・HPへのダメージ処理実装
スキルの実装はおもに以下の2クラスを作成して行います。
- SkillData.cs:スキル名や効果、使用できる対象や消費TPといったスキルデータを登録できるScriptableObject
- SkillEffect.cs:各スキル効果の使用時の処理を担当
まずはSkillEffectクラスから作成していきます。
スキル使用時に呼び出されるメソッドは全スキルで共通化したいため、ここでもクラスの継承を用います。
SkillEffect.cs (新規)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; /// <summary> /// スキル効果の基底クラス /// </summary> [Serializable] public class SkillEffect { /// <summary> /// スキル使用時の対象への効果 /// </summary> /// <param name="battleManager">バトルマネージャークラスへの参照(Battleシーン以外から呼出ならnull)</param> /// <param name="casterData">スキル使用者のCharacterData</param> /// <param name="targetData">スキル使用対象のCharacterData</param> /// <param name="effectValue">スキル効果量倍率</param> public virtual void ApplyEffectToTarget (BattleManager battleManager, CharacterData casterData, CharacterData targetData, float effectValue) { } } /// <summary> /// スキル効果:ダメージ /// </summary> [Serializable] public class DamageEffect : SkillEffect { [Header ("攻撃スキル設定")] public float damagePower; // ダメージ倍率 /// <summary> /// スキル使用時の効果(戦闘スキル) /// </summary> public override void ApplyEffectToTarget (BattleManager battleManager, CharacterData casterData, CharacterData targetData, float effectValue) { // ダメージ量 int damageValue = 0; // デバッグ用にダメージ量は固定値にする damageValue = 20; // ダメージを対象に適用 if (battleManager != null) { battleManager.ChangeCharacterHP (targetData, -damageValue); } } } |
全スキル効果クラスの基底クラスとなるSkillEffectを作成し、それをもとに「相手にダメージを与える効果」を扱うDamageEffectクラスを作成しています。
戦闘中に使用される場合はApplyEffectToTargetメソッドが呼び出されます。スキルを使用するキャラのデータおよび対象となるキャラのデータがそれぞれ引数で渡されるので、それをもとにダメージ計算を行ってHPに反映させます。
HPの変更はBattleManagerクラスを介して行う形にします。こうすることで後々演出などを追加しやすくなります。よってBattleManagerクラスとCharacterDataクラス、ActorUIクラスを引き続き編集していきます。
BattleManager.cs
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
using System.Collections.Generic; using UnityEngine; /// <summary> /// (Battle) /// バトルマネージャー /// </summary> public class BattleManager : MonoBehaviour { // オブジェクト・コンポーネント参照 public EnemyManager enemyManager; // エネミーマネージャ // オブジェクト・コンポーネント参照 // アクターUI [SerializeField] private List<ActorUI> actorUI_Vanguard = null; // 前衛アクターUI参照 [SerializeField] private List<ActorUI> actorUI_Rearguard = null; // 後衛アクターUI参照 private List<ActorUI> actorUIs; // 前衛・後衛を足したアクターUIリスト // 戦闘に参加している全キャラクターのリスト public List<CharacterData> battleCharacterDatas { get; private set; } // テスト用・戦闘に参加するエネミーのデータ public List<EnemyData> debugBattleEnemyDatas; // Start void Start () { // 変数初期化 battleCharacterDatas = new List<CharacterData> (); // 管理下コンポーネント初期化 enemyManager.Init (this); // アクターUI初期化 // 前衛リストと後衛リストをまとめたリストを作成 actorUIs = new List<ActorUI> (actorUI_Vanguard); actorUIs.AddRange (actorUI_Rearguard); // リストを加算 // 前衛 for (int i = 0; i < actorUI_Vanguard.Count; i++) { if (i < Data.instance.formationDatas_Vanguard.Count) { // アクターUI初期化 actorUI_Vanguard[i].Init (this, Data.instance.formationDatas_Vanguard[i]); // 戦闘参加キャラクターリストに追加 battleCharacterDatas.Add (Data.instance.formationDatas_Vanguard[i]); } else actorUI_Vanguard[i].DisableActorUI (); } // 後衛 for (int i = 0; i < actorUI_Rearguard.Count; i++) { if (i < Data.instance.formationDatas_Rearguard.Count) { // アクターUI初期化 actorUI_Rearguard[i].Init (this, Data.instance.formationDatas_Rearguard[i]); // 戦闘参加キャラクターリストに追加 battleCharacterDatas.Add (Data.instance.formationDatas_Rearguard[i]); } else actorUI_Rearguard[i].DisableActorUI (); } // デバッグ用エネミー出現処理 foreach (var enemyData in debugBattleEnemyDatas) {// 各エネミーインスタンスをLevel1で作成 enemyManager.CreateEnemyData (enemyData, 1); } } #region キャラクターステータス変動処理 /// <summary> /// 現在HPを変更する /// </summary> /// <param name="targetChara">対象CharacterData</param> /// <param name="value">変化量(マイナス値でダメージ、プラス値で回復)</param> public void ChangeCharacterHP (CharacterData targetChara, int value) { // ステータス変動 targetChara.ChangeNowHP (value); // 戦闘不能状態に突入する判定(今は使用しない) bool isKnockOut = false; if (targetChara.currentHP <= 0 && !targetChara.isKnockedOut) isKnockOut = true; // 対象キャラクターのUI更新および戦闘不能時処理 foreach (var actorUI in actorUIs) if (actorUI.actorData == targetChara) { // UI表示更新 actorUI.RefreshUI (); // 戦闘不能時処理 if (isKnockOut) actorUI.StartKnockOut (); } } #endregion } |
このあとCharacterDataクラスに追加するHP変更処理を呼び出し、あわせて戦闘不能時(HPが0になった時)に呼び出す処理についても用意しておきます。
戦闘不能になるとそのCharacterDataのisKnockedOutフラグがtrueになり、ターンがまわってこなくなるなどの処理がこれから追加されていきます。
CharacterData.cs
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
using System.Collections.Generic; using UnityEngine; /// <summary> /// キャラクターデータ定義クラス(敵味方共通の基底クラス) /// </summary> [System.Serializable] public class CharacterData : ScriptableObject { // キャラクター名 [HideInInspector] public string characterName; // 現在ステータス [HideInInspector] public int currentHP; // 現在HP [HideInInspector] public int currentTP; // 現在TP [HideInInspector] public bool isKnockedOut; // 戦闘不能フラグ // 現在の状態異常と残りターン数(Dictionaryによってペアで管理) [HideInInspector] public Dictionary<CharacterState, int> currentStates; // 基礎能力 public int baseMaxHP; // 最大HP public int baseMaxTP; // 最大TP public int baseAtk; // 物理攻撃力 public int baseDef; // 物理防御力 public int baseMAtk; // 魔法攻撃力 public int baseMDef; // 魔法防御力 public int baseLuc; // 運 public int baseSpeed; // 速度 // 属性耐性(0.0fが基準、1.0fでダメージ無効化、-1.0fでダメージ2倍) public float resist_Fire; // 火耐性 public float resist_Ice; // 氷耐性 public float resist_Light; // 光耐性 public float resist_Dark; // 闇耐性 // 定数定義 private const float StatusBuffMulti = 1.5f; // ステータス上昇系のバフがある場合の計算時倍率 private const float StatusDebuffMulti = 0.6f; // ステータス低下系のデバフがある場合の計算時倍率 #region 現在ステータス変更 /// <summary> /// 現在HPを変更する /// </summary> public void ChangeNowHP (int value) { // 戦闘不能時は処理しない if (isKnockedOut) return; // 現在HPを増減 currentHP += value; // 現在HPを0から最大HPまでの値に収める currentHP = Mathf.Clamp (currentHP, 0, GetCalculatedMaxHP ()); } /// <summary> /// 現在TPを変更する /// </summary> public void ChangeNowTP (int value) { // 戦闘不能時は処理しない if (isKnockedOut) return; // 現在TPを増減 currentTP += value; // 現在TPを0から最大TPまでの値に収める currentTP = Mathf.Clamp (currentTP, 0, GetCalculatedMaxTP ()); } /// <summary> /// ステータス全回復 /// </summary> public void FullRecoveryStatus () { // 戦闘不能フラグ解除 isKnockedOut = false; // 全状態異常解除 RemoveAllStates (); // HP全回復 currentHP = GetCalculatedMaxHP (); // TP全回復 currentTP = GetCalculatedMaxTP (); } #endregion #region 状態異常関連 /// <summary> /// 状態異常をセットする /// </summary> public void SetState (CharacterState targetState, int turnNum) { // 戦闘不能時は処理しない if (isKnockedOut) return; // 状態異常追加 if (currentStates.ContainsKey (targetState)) {// 既に該当の状態異常にかかっている // 残りターン数を更新 if (currentStates[targetState] < turnNum) currentStates[targetState] = turnNum; } else {// 新規付与 // 状態異常DictionaryにKey(状態異常の種類)とValue(残りターン数)を追加 currentStates.Add (targetState, turnNum); } } /// <summary> /// 状態異常を解除する /// </summary> public void RemoveState (CharacterState targetState) { // 状態異常解除(状態異常DictionaryからKeyを削除) if (currentStates.ContainsKey (targetState)) currentStates.Remove (targetState); } /// <summary> /// 全ての状態異常を解除する /// </summary> public void RemoveAllStates () { // 状態異常Dictionaryを初期化 currentStates.Clear (); } /// <summary> /// 全状態異常残りターンを1ずつ減らす /// </summary> public void DecreaseCharacterStates () { // 状態異常Dictionary内のKeyをリストで取得 List<CharacterState> states = new List<CharacterState> (currentStates.Keys); // 各KeyごとにDictionary内で格納している残りターン数をデクリメント foreach (var targetState in states) { currentStates[targetState]--; // 残りターン数が0以下ならDictionaryからKeyを削除 if (currentStates[targetState] <= 0) currentStates.Remove (targetState); } } #endregion #region 計算後ステータス取得 // MaxHP取得 public virtual int GetCalculatedMaxHP () { return baseMaxHP; } // MaxTP取得 public virtual int GetCalculatedMaxTP () { return baseMaxTP; } // Atk取得 public virtual int GetCalculatedAtk () { return baseAtk; } // Def取得 public virtual int GetCalculatedDef () { return baseDef; } // MAtk取得 public virtual int GetCalculatedMAtk () { return baseMAtk; } // MDef取得 public virtual int GetCalculatedMDef () { return baseMDef; } // Luc取得 public virtual int GetCalculatedLuc () { return baseLuc; } // Speed取得 public virtual int GetCalculatedSpeed () { int value = baseSpeed; // 状態異常による補正を適用 if (currentStates.ContainsKey (CharacterState.SpeedUp)) value = (int)(value * StatusBuffMulti); if (currentStates.ContainsKey (CharacterState.SpeedDown)) value = (int)(value * StatusDebuffMulti); return value; } // 各種耐性値取得 public virtual float GetCalculatedResist (ElementType elementType) { float value; switch (elementType) { case ElementType.Fire: // 火耐性 value = resist_Fire; break; case ElementType.Ice: // 氷耐性 value = resist_Ice; break; case ElementType.Light: // 光耐性 value = resist_Light; break; case ElementType.Dark: // 闇耐性 value = resist_Dark; break; default: // その他 value = 0.0f; break; } return value; } #endregion #region 属性ダメージ倍率取得 /// <summary> /// 指定した属性の攻撃スキルを受けた時のダメージ倍率を返す /// </summary> public float GetElementDamage (ElementType elementType) { // 各属性の耐性値を取得 float resistValue = GetCalculatedResist (elementType); // ダメージ倍率を計算して返す return 1.0f - resistValue; } #endregion } // (enum)キャラクター状態異常 public enum CharacterState { Poison, // 毒 Stun, // スタン Protection, // かばう Mark, // 標的 Guard, // ガード SpeedUp, // 速度上昇 SpeedDown, // 速度低下 MagicWall, // 魔法壁 } // (enum)属性種類 public enum ElementType { None, // 無属性 Fire, // 火属性 Ice, // 氷属性 Light, // 光・雷属性 Dark, // 闇属性 } |
HPとTPの変更処理、今は使用しませんが全回復の処理まであらかじめ用意しておきます。
ActorUI.cs
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
using UnityEngine; using UnityEngine.UI; using TMPro; /// <summary> /// (Battle) BattleManager配下 /// アクターUI処理クラス /// </summary> public class ActorUI : MonoBehaviour { // オブジェクト・コンポーネント [HideInInspector] public BattleManager battleManager; // バトルマネージャ参照 // 外枠Image [SerializeField] private Image frameImage = null; // アクター顔グラフィックImage [SerializeField] private Image actorIconImage = null; // アクター名Text [SerializeField] private TextMeshProUGUI nameText = null; // 現在HPText [SerializeField] private TextMeshProUGUI hpText = null; // HPゲージImage [SerializeField] private Image hpGage = null; // 現在TPText [SerializeField] private TextMeshProUGUI tpText = null; // TPゲージImage [SerializeField] private Image tpGage = null; // このUIが対応するアクターデータ public ActorData actorData { get; private set; } // 各種変数 public bool isAbleUI; // UI有効フラグ // 初期化関数(BattleManager.csから呼出) public void Init (BattleManager _battleManager, ActorData _actorData) { // 参照取得 battleManager = _battleManager; actorData = _actorData; // 変数初期化 isAbleUI = true; // UI初期化 nameText.text = actorData.characterName; actorIconImage.sprite = Data.instance.ActorFaceIconsRess[actorData.pictureID]; RefreshUI (); } /// <summary> /// このアクターUIを無効化する /// </summary> public void DisableActorUI () { gameObject.SetActive (false); isAbleUI = false; } /// <summary> /// ステータスUIの表示を更新する /// </summary> public void RefreshUI () { // このUIが無効化中なら処理しない if (!isAbleUI) return; // HP表示 hpText.text = actorData.currentHP + "<size=60%><color=#222>/" + actorData.baseMaxHP + "</color></size>"; hpGage.fillAmount = (float)actorData.currentHP / actorData.baseMaxHP; // TP表示 tpText.text = actorData.currentTP + "<size=60%><color=#222>/" + actorData.baseMaxTP + "</color></size>"; tpGage.fillAmount = (float)actorData.currentTP / actorData.baseMaxTP; } /// <summary> /// 戦闘不能状態突入時処理 /// </summary> public void StartKnockOut () { // 戦闘不能設定 actorData.isKnockedOut = true; nameText.color = Color.red; // 状態異常消去 actorData.currentStates.Clear (); } } |
こちらも今すぐに特別な処理を行うことはありませんが、キャラクターが戦闘不能になった時に処理や演出を行うメソッドも用意しておきます。
戦闘不能になると名前を赤色で表示して分かりやすくなるようにします。
4クラスの編集によって、DamageEffectクラスのApplyEffectToTargetメソッドを呼び出すことにより対象キャラクターのHPを減少できるようになりました。
日本語・英語の文章設定機能
引き続きスキルデータの実装に移りますが、その前にこのゲームに言語設定を反映できるよう準備を進めておきます。
このゲームは日本語と英語の2言語の表示に対応しているので、現在の言語設定をDataクラスから取得し、それに応じた文章をスクリプトから設定できるようにしましょう。
Data.cs
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
using System.Collections.Generic; using UnityEngine; /// <summary> /// (DataManager) /// データマネージャー /// </summary> public class Data : MonoBehaviour { #region シングルトン維持用処理(変更不要) // シングルトン維持用 public static Data instance { get; private set; } // Awake private void Awake () { // シングルトン用処理 if (instance != null) {// 既にシーン内にインスタンスが存在済みなら自身を破棄 Destroy (gameObject); return; } instance = this; // // シーン遷移時にオブジェクトを破棄しない設定 DontDestroyOnLoad (gameObject); // ゲーム起動時処理 InitialProcess (); } #endregion // オプション設定データ public static SystemLanguage nowLanguage; // 現在の設定言語 // ゲームデータ [HideInInspector] public List<ActorData> actorDatas; // 全アクターデータ [HideInInspector] public List<ActorData> formationDatas_Vanguard; // 隊列データ:前衛 [HideInInspector] public List<ActorData> formationDatas_Rearguard; // 隊列データ:後衛 // ゲームリソース public List<Sprite> ActorPicturesRess; // アクター立ち絵画像リスト public List<Sprite> ActorFaceIconsRess; // アクター顔画像リスト // 各種定数 public const int Character_BaseStatus_Multi = 5; // キャラクター能力値倍率(レベル1のキャラクターの各能力値はベース値にこの値を掛けたものになる) /// <summary> /// ゲーム開始時(インスタンス生成時)に一度だけ実行される処理 /// </summary> private void InitialProcess () { // 乱数シード値初期化 Random.InitState (System.DateTime.Now.Millisecond); // (スマートフォン用)動作FPS設定 Application.targetFrameRate = 60; // ゲームデータ初期化 InitGameDatas (); } /// <summary> /// ゲームデータ初期化処理 /// </summary> public void InitGameDatas () { // キャラデータ初期化 actorDatas = new List<ActorData> (); formationDatas_Vanguard = new List<ActorData> (); formationDatas_Rearguard = new List<ActorData> (); // その他ゲームデータ初期化 nowLanguage = (SystemLanguage)(-1); // デバッグ用のテストアクターデータ作成 DebugActorCreate (); // 初期言語設定 if (nowLanguage == (SystemLanguage)(-1)) { // プレイ環境の言語設定から取得 nowLanguage = Application.systemLanguage; // 日本語・英語以外の言語だった場合全て英語で対応する if (nowLanguage != SystemLanguage.Japanese && nowLanguage != SystemLanguage.English) nowLanguage = SystemLanguage.English; } } #region アクターデータ関連 /// <summary> /// デバッグ用のテストアクターデータ作成 /// </summary> private void DebugActorCreate () { // 立ち絵ID0のキャラクター作成 actorDatas.Add (CreateCharacterData (0)); // 前衛に追加 formationDatas_Vanguard.Add (actorDatas[0]); } /// <summary> /// アクターデータを新規作成する /// </summary> public ActorData CreateCharacterData (int pictureID) { // ActorDataインスタンス作成 ActorData actorData = ScriptableObject.CreateInstance<ActorData> (); // 立ち絵画像ID設定 actorData.pictureID = pictureID; // 基礎ステータス設定 actorData.baseMaxHP = Random.Range (3, 8) * Character_BaseStatus_Multi; actorData.currentHP = actorData.baseMaxHP; actorData.baseMaxTP = Random.Range (3, 8) * Character_BaseStatus_Multi; actorData.currentTP = actorData.baseMaxTP; actorData.baseAtk = Random.Range (3, 8) * Character_BaseStatus_Multi; actorData.baseDef = Random.Range (3, 8) * Character_BaseStatus_Multi; actorData.baseMAtk = Random.Range (3, 8) * Character_BaseStatus_Multi; actorData.baseMDef = Random.Range (3, 8) * Character_BaseStatus_Multi; actorData.baseLuc = Random.Range (3, 8) * Character_BaseStatus_Multi; actorData.baseSpeed = Random.Range (35, 66); // 状態異常リスト初期化 actorData.currentStates = new Dictionary<CharacterState, int> (); // 耐性値設定 actorData.resist_Fire = 0.0f; actorData.resist_Ice = 0.0f; actorData.resist_Light = 0.0f; actorData.resist_Dark = 0.0f; // その他パラメータ設定 actorData.nowLevel = 1; actorData.nowEXP = 0; actorData.maxEXP = 0; return actorData; } /// <summary> /// Battleに参加する全アクターデータを1つのリストにして返す /// </summary> public List<ActorData> GetBattleActorDatas () { // 前衛・後衛アクターデータリストを合わせたリストを作成 List<ActorData> allActorsList = new List<ActorData> (instance.formationDatas_Vanguard); allActorsList.AddRange (instance.formationDatas_Rearguard); return allActorsList; } #endregion } |
SystemLanguage型には各言語名がenumで定義されています。これを用いて言語設定を記憶します。
初期化メソッド内にてこのゲームをプレイ中の環境設定に応じた言語を取得します。環境が日本語でも英語でもなかった場合は英語になるよう設定します。
これで言語設定を使用できるようになったため、既存のEnemyData作成処理にて暫定的に日本語名のみを使用していた処理を変更します。
EnemyManager.cs
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
using System.Collections.Generic; using UnityEngine; /// <summary> /// (GameMain) BattleManager配下 /// エネミーマネージャ /// </summary> public class EnemyManager : MonoBehaviour { // オブジェクト・コンポーネント参照 public BattleManager battleManager { get; private set; } // エネミーUIプレハブ [SerializeField] private GameObject enemyUIPrefab = null; // プレハブ参照 [SerializeField] private Transform enemyUIsParent = null; // インスタンスの親Transform参照 // 出現中の敵リスト public List<EnemyData> enemyDatas { get; private set; } // 各敵に対応するエネミーUI参照Dictionary public Dictionary<EnemyData, EnemyUI> enemyUIs { get; private set; } // 初期化関数(BattleManager.csから呼出) public void Init (BattleManager _battleManager) { // 参照取得 battleManager = _battleManager; // 変数初期化 enemyDatas = new List<EnemyData> (); enemyUIs = new Dictionary<EnemyData, EnemyUI> (); } /// <summary> /// エネミーデータからその敵を作成する /// </summary> public void CreateEnemyData (EnemyData targetEnemyData, int level) { // 渡されたエネミーデータを基に新規EnemyDataインスタンス作成 EnemyData enemyData = Instantiate (targetEnemyData); // エネミーデータ設定 // 言語設定に応じた名前を取得 if (Data.nowLanguage == SystemLanguage.Japanese) enemyData.characterName = targetEnemyData.enemyName_JP; // 日本語 else enemyData.characterName = targetEnemyData.enemyName_EN; // 英語 // 各ステータスをコピー&レベル反映 int multiValue = 5; // エネミーレベル未実装なので5の固定倍率を適用 enemyData.baseMaxHP = targetEnemyData.baseMaxHP * multiValue; enemyData.currentHP = targetEnemyData.baseMaxHP * multiValue; enemyData.baseMaxTP = targetEnemyData.baseMaxTP * multiValue; enemyData.currentTP = targetEnemyData.baseMaxTP * multiValue; enemyData.currentStates = new Dictionary<CharacterState, int> (); enemyData.baseAtk = targetEnemyData.baseAtk * multiValue; enemyData.baseDef = targetEnemyData.baseDef * multiValue; enemyData.baseMAtk = targetEnemyData.baseMAtk * multiValue; enemyData.baseMDef = targetEnemyData.baseMDef * multiValue; enemyData.baseLuc = targetEnemyData.baseLuc * multiValue; enemyData.baseSpeed = targetEnemyData.baseSpeed; enemyData.resist_Fire = targetEnemyData.resist_Fire; enemyData.resist_Ice = targetEnemyData.resist_Ice; enemyData.resist_Light = targetEnemyData.resist_Light; enemyData.resist_Dark = targetEnemyData.resist_Dark; // その他敵専用データをコピー enemyData.enemyName_JP = targetEnemyData.enemyName_JP; enemyData.enemyName_EN = targetEnemyData.enemyName_EN; enemyData.standingSprite = targetEnemyData.standingSprite; enemyData.faceIconSprite = targetEnemyData.faceIconSprite; enemyData.enemyExp = targetEnemyData.enemyExp; enemyData.enemyGold = targetEnemyData.enemyGold; // 出現中敵リストに追加 enemyDatas.Add (enemyData); battleManager.battleCharacterDatas.Add (enemyData); // UI作成 CreateEnemyUI (enemyData); } /// <summary> /// エネミーUIを作成する /// </summary> private void CreateEnemyUI (EnemyData enemyData) { // UIオブジェクト作成 var obj = Instantiate (enemyUIPrefab, enemyUIsParent); // 処理クラスへの参照を取得しDictionaryに格納 var enemyUI = obj.GetComponent<EnemyUI> (); enemyUIs.Add (enemyData, enemyUI); // 処理クラス初期化 enemyUI.Init (this, enemyData); } } |
このあたりの敵名などの言語変化は7章で敵名を表示するUIに拡張した際に使われます。また、この後のスキルデータクラス実装の際にも言語変化に対応させていきます。
スキルデータクラスの実装
このゲームにおけるスキルはアクティブスキル(使用することで効果を発動するもの)とパッシブスキル(習得しているだけで効果を発揮し続けるもの)の2種類に大別できます。当面はアクティブスキルのみを実装します。
またスキルの習得に関する機能は後々実装しますが、スキルの習得にはSP(スキルポイント)を追加で消費することでスキルレベルを上昇させられるようにします。同じスキルでもスキルレベルが高ければ、より高い消費TPと引き換えにより高い効果量を発揮できるようになります。
このあたりの機能は世界樹の迷宮などでもお馴染みの形式ですね。
スキルデータの定義においては各スキルレベルごとの効果量倍率および消費TPを設定できるように工夫していきます。
また前述したように、1つのスキルでも複数のSkillEffectを持つ場合があるので注意して実装します。
それではスキルデータをScriptableObjectとして登録できるようにしていきましょう。SkillDataクラスを作成します。
SkillData.cs (新規)
まとめ
戦闘システムの1つとして重要な要素であるスキルについて実装を進めることができました。
次回からはカウントタイムバトルシステムの開発に着手していきます。各キャラクターにターンを回して、そのキャラクターがスキルを使用できるような状態を目指しましょう。
次の記事:

現場レベルのゲーム制作が、すべてここで学べます。






コメント