回合式類寶可夢精靈對戰系統
回合式類寶可夢精靈對戰系統
github連結(https://github.com/z-hwa/SummonersGame)
系統概述
主要是完成回合式對戰遊戲中的戰鬥場景,並實現精靈、技能、屬性、個性等等系統
當遊戲啟動以後,將會自動載入預先創建好的精靈雪莉,接著載入敵人,同樣也是雪莉。
整個遊戲的狀態,由Unity內建的Debug.log函數做輸出,並沒有實現在遊戲窗口的狀態廣播。
首先會進行雙方單位的速度能力值比較(相同的情況下,預設為玩家方優先),並進入對應單位的回合。
進入整個以IEnumerator為主的循環中,並在回合操作後,檢測雙方的背包中,是否仍有可行動的單位。
判斷是否進入勝敗的狀況,或是進到對方的IEnumerator函數中,等待下一步操作。
主邏輯
初始化
以BattleSystem為戰鬥中的主流程操控。
並透過Enum來紀錄當前的場景狀況。
//系統可能的狀態
public enum BattleState {
START = 0,
PLAYERTURN,
ENEMYTURN,
WON,
LOSE
}
BattleSystem預設以UnitBattleData創建兩個實體,並在開始時,載入雙方的單位資料,分別代表玩家以及敵人,在戰鬥中的所有數據紀錄
接著BattleSystem呼叫UISystem的LoadUIData(),載入所有的UI資訊
下一步,透過BattleSystem內的PreemtiveTest()函數,進行速度比較。
接著,進入IEnumerator中(雙方回合)。
玩家回合
利用Unity的Button等待玩家進行動作
- 施放技能
- 透過BattleSystem呼喚SkillSystem的UsingSkll()函數,施放技能
- 更換精靈
- 透過BattleSystem下的ChooseUnit()來更換精靈
- 並透過BattleSystem下的UISystem來更新UI
透過UISystem更新UI
檢測敵人是否輸了
- 是:進入勝利狀態,結束遊戲
- 否:進入敵人回合,繼續遊戲
敵人回合
BattleSystem呼叫EnemyAISystem中的AIModeUsing,switch進該名敵方單位設定的AI模式呼叫
根據AI模式,傳回該使用的技能ID
- 透過BattleSystem呼喚SkillSystem的UsingSkll()函數,施放技能
檢測玩家是否輸了
- 是:進入勝利狀態,結束遊戲
- 否:進入玩家回合,繼續遊戲
BattleSystem
玩家IEnumerator
//玩家回合
IEnumerator PlayerTurn()
{
bool isEnemyLose = false; //標示敵人是否戰敗
isUsingSkill = false; //檢測是否施放技能
OnInteractable_SkillButton(); //激活技能按鍵
Debug.Log("你的回合 請選擇......");
yield return new WaitUntil(() => isUsingSkill); //等待直到施放技能
yield return new WaitForSeconds(2f); //等待技能動畫或技能效果實現
/*
RenewUIData(); //更新UI
isEnemyLose = CheckEnemyIsLose(); //檢測敵人是否輸了
/* 兩種情況的檢測
* 進入敵方回合
* 勝利
*/
if(isEnemyLose == true)
{
Debug.Log("你勝利了");
battleState = BattleState.WON;
//BattleWon();
}else
{
battleState = BattleState.ENEMYTURN;
StartCoroutine(EnemyTurn()); //敵人回合
}
}
敵人IEnumerator
//敵方回合
IEnumerator EnemyTurn()
{
int playerStatus = 0; /* 標示玩家是否戰敗
* 0 未戰敗 可繼續戰鬥
* 1 戰敗
* 2 當前單位戰敗 但可以更換單位繼續戰鬥
*/
int skillID = -1; //將要進行的技能ID
Debug.Log("敵方回合......");
Debug.Log("敵方發起攻擊");
skillID = enemyAISystem.AIModeUsing(enemyBattleData.enemyAIID); //從AI系統 獲得敵人行為模式
skillSystem.UsingSkill(skillID, enemyBattleData, playerBattleData); //發動技能
yield return new WaitForSeconds(2f); //等待技能動畫或技能效果實現
RenewUIData(); //更新UI
playerStatus = CheckPlayerIsLose(); //檢測玩家是否輸了
/* 兩種情況的檢測
* 進入敵方回合
* 勝利
*/
if (playerStatus == 1)
{
Debug.Log("你輸拉");
battleState = BattleState.LOSE;
//BattleLose();
}
else if(playerStatus == 0)
{
battleState = BattleState.PLAYERTURN;
StartCoroutine(PlayerTurn()); //玩家回合
}
else if(playerStatus == 2)
{
Debug.Log("當前單位戰敗 請更換單位!");
battleState = BattleState.PLAYERTURN;
StartCoroutine(PlayerTurn()); //玩家回合
}
}
戰鬥系統的核心邏輯腳本
基本上就是讓流程在兩個IEnumerator中,去進行
並在發生終止條件(比出勝負)後,跳出這個IEnumerator中
單位系統
單位系統是多個子系統的概念複合體,包含了以下數個腳本、實體系統
- UnitObject(Scriptal Object):
- 腳本資料
- 包含一個腳色的所有資訊
- 紀錄一種精靈的設定(不變動)
- UnitBattleData:
- 作為精靈背包資料的實體(6格)
- 作為玩家、敵人資料的變數(2格)
- 會從UnitObject中載入精靈資料
- 更換精靈時,即是直接將背包資料的實體ref,賦給玩家資料的變數
- CharacterSystem:
- 記錄所有精靈的個性(影響升級時的能力值分配)
- 記錄所有個性的能力值分配方式
- AttributeSystem:
- 記錄所有精靈的屬性
- 記錄所有屬性的克制關係
- EnemyAISystem:
- 統整併處理敵人AI的使用
- 在Scripts/Enemy/AI下,放置各種AI模式的腳本
- 需要手動添加新的AI模式到代碼裡
- PackageSystem:
- 保存6個UnitBattleData的實體
- 用於野外場景到戰鬥場景的資料傳輸by SO
- 用於戰鬥場景的初始化
SkillSystem
用於處理所有的技能施放,並根據使用的技能ID,找到對應的技能代碼,產生效果
//根據ID施放技能
public void UsingSkill(int skillID, UnitBattleData attaker, UnitBattleData defensor)
{
switch (skillID)
{
case 0:
UseSkill_0(attaker, defensor);
break;
default:
Debug.Log("查無檢索");
break;
}
}
也包含透過技能ID,查找SkillData實體,保存的技能資料,以讓UISystem可以顯示技能資訊
//根據ID找到技能的名稱
public string CheckSkillName(int skillID)
{
//確認當前資料庫長度
//預設目標技能index為0
int dataSize = skillData.data.Length;
int targetSkill_Index = 0;
//遍歷資料庫查詢技能
for(int i=0;i<dataSize;i++)
{
if(skillID == skillData.data[i].ID)
{
//找到 設定目標index
targetSkill_Index = i;
break;
}else
{
//沒有找到
Debug.Log("do not find the " + skillID + " ID skill in data");
}
}
return skillData.data[targetSkill_Index].skillName;
}
技能資料的儲存,同樣透過SO(Scriptal Object)的方式完成
[CreateAssetMenu(fileName = "skill", menuName = "Unit/New Skill")]
public class SkillObject : ScriptableObject
{
[Header("技能敘述")]
public string skillName;
public int ID;
public int learnLevel;
public int power;
public int pp;
[TextArea] public string skillEffect; //技能效果
[TextArea] public string skillIntro; //技能敘述
}
新資料創建
單位
透過UnitObject的SO,快速創建精靈的單位(根据設定集)
技能
透過SkillData的SO,創建精靈的技能描述、文本資料
並在SkillSystem中,完成相對ID的技能程式碼
個性
在CharacterSystem中,可以直接創建新的個性Enum
並設定相關的升級數值分配方式
屬性
在AttributeSystem中,可以直接創建新的屬性Enum
並設定相關的屬性克制倍率
AI
在Scripts/Enemy/AI中,撰寫新的AI腳本
並在EnemyAISystem中,添加該腳本用於呼叫
(預設為單位的ID,直接使用該ID的AI腳本,如果沒有該ID的AI腳本,則使用Default)
參考資料
Turn-Based Combat in Unity, from https://www.youtube.com/watch?v=_1pz_ohupPs
[Unity3D]ScriptableObject解析,來自
https://zhuanlan.zhihu.com/p/417241353
C# 拷贝数组的几种方法,來自 https://www.cnblogs.com/makesense/p/4461016.html
Unity Editor | 系列簡介與Inspector 小技巧 #1,來自 https://vocus.cc/article/63db8783fd89780001454ccf
Unity 中 创建 TextMeshPro 中文字体(含常见汉字 TXT 文件),來自 https://blog.csdn.net/qq_37454669/article/details/121128100
Unity进阶:ScriptableObject使用指南,來自 https://blog.csdn.net/qq_46044366/article/details/124310241
赛尔号伤害计算公式,來自 https://news.4399.com/seer/jingyanxinde/201209-05-194310.html
C# 枚举(Enum),來自https://www.runoob.com/csharp/csharp-enum.html
Unity不同脚本之间的执行顺序,來自https://gwb.tencent.com/community/detail/128278
Unity Coroutine 使用筆記,來自https://dev.twsiyuan.com/2017/05/unity-coroutine.html
ScriptableObjects, image files and UI Image, from https://forum.unity.com/threads/scriptableobjects-image-files-and-ui-image.886486/