《Unityで作るリズムゲーム》學習筆記(九):「分數與Combo」-完結
書名:《Unityで作るリズムゲーム》
作者:長崎大学マルチメディア研究会
計算與邏輯
-
對於遊戲分數和Combo的計算,不同音遊有不同的計分方法
- 最大得分
- 與note數量無關
- 取決於note數量
- Combo對得分的影響
- 不影響得分
- Combo數越高,每個note的得分越高
- Long Note分數/Combo處理
- 起/終點各自撃中增加分數和Combo數
- 分數和Combo數僅在起點/終點增加
- Long Note進入處理狀態後,Combo和分數會持續增加
- 最大得分
-
在本案例中,會使用以下標準
- 最大得分取決於notes數量
- Combo不影響得分
- 起點和終點被分別撃中時都有加分和Combo
-
評價管理器(EvaluationManager)
-
在該管理器中,主要需要處理分數的增加和Combo數的計算,為了進行這兩者的計算,首先要準備一些字段。
-
//分數上限 public static readonly float theoreticalScore = 1000000; //評價得分倍率 static readonly Dictionary<JudgementType, float> scoreAddRates = new Dictionary<JudgementType, float> { {JudgementType.PERFECT, 1.0f }, {JudgementType.GOOD, 0.5f }, {JudgementType.BAD, 0.2f }, {JudgementType.MISS, 0.0f } }; public static float score; //當局得分 public static int combo; //當局連撃數 public static int maxCombo; //譜面遊玩歷史最大連撃數 public static int theoreticalCombo; //該譜面的可能最大連撃數 //每種評價的數量 public static Dictionary<JudgementType, int> judgementCounts = new Dictionary<JudgementType, int>();
-
-
要知道每一個note佔多少分,首先要計算當前譜面有多少個note。
-
//值初始化 private void Start() { score = 0f; combo = 0; maxCombo = 0; judgementCounts[JudgementType.PERFECT] = 0; judgementCounts[JudgementType.GOOD] = 0; judgementCounts[JudgementType.BAD] = 0; judgementCounts[JudgementType.MISS] = 0; //最大可能連撃數 theoreticalCombo = PlayerController.beatMap.noteDatas .Count(note => note.noteType == NoteType.Single) + PlayerController.beatMap.noteDatas .Count(note => note.noteType == NoteType.Long) * 2; } public static void OnHit(JudgementType judgementType) { combo++; //每個note的分數 float addValue = theoreticalScore / theoreticalCombo; //每個note的分數 * 得分倍率 score += addValue * scoreAddRates[judgementType]; judgementCounts[judgementType]++; }
-
-
Combo的判定在Note的撃中和Miss時都要記錄(增加/斷連)
-
private void Update() { //持續更新最大Combo數 maxCombo = Mathf.Max(combo, maxCombo); } //斷連 public static void OnMiss() { combo = 0; judgementCounts[JudgementType.MISS]++; }
-
-
總體代碼
-
using System.Collections.Generic; using System.Linq; using UnityEngine; public class EvaluationManager : MonoBehaviour { //分數上限 public static readonly float theoreticalScore = 1000000; //評價得分倍率 static readonly Dictionary<JudgementType, float> scoreAddRates = new Dictionary<JudgementType, float> { {JudgementType.PERFECT, 1.0f }, {JudgementType.GOOD, 0.5f }, {JudgementType.BAD, 0.2f }, {JudgementType.MISS, 0.0f } }; public static float score; //當局得分 public static int combo; //當局連撃數 public static int maxCombo; //譜面遊玩歷史最大連撃數 public static int theoreticalCombo; //該譜面的可能最大連撃數 //每種評價的數量 public static Dictionary<JudgementType, int> judgementCounts = new Dictionary<JudgementType, int> { { JudgementType.PERFECT, 0 }, { JudgementType.GOOD, 0 }, { JudgementType.BAD, 0 }, { JudgementType.MISS, 0 }, }; //值初始化 private void Start() { score = 0f; combo = 0; maxCombo = 0; judgementCounts[JudgementType.PERFECT] = 0; judgementCounts[JudgementType.GOOD] = 0; judgementCounts[JudgementType.BAD] = 0; judgementCounts[JudgementType.MISS] = 0; //最大可能連撃數 theoreticalCombo = PlayerController.beatMap.noteDatas .Count(note => note.noteType == NoteType.Single) + PlayerController.beatMap.noteDatas .Count(note => note.noteType == NoteType.Long) * 2; } private void Update() { //持續更新最大Combo數 maxCombo = Mathf.Max(combo, maxCombo); } public static void OnHit(JudgementType judgementType) { combo++; //每個note的分數 float addValue = theoreticalScore / theoreticalCombo; //每個note的分數 * 得分倍率 score += addValue * scoreAddRates[judgementType]; judgementCounts[judgementType]++; } //斷連 public static void OnMiss() { combo = 0; judgementCounts[JudgementType.MISS]++; } }
-
-
-
在SingleNoteController和LongNoteController的判定後方法中調用評價管理器中對應的處理
-
SingleNoteController
-
void CheckMiss() { if (noteProperty.secBegin - PlayerController.currentSec < -JudgementManager.judgementWidth[JudgementType.BAD]) { //斷連 EvaluationManager.OnMiss(); //... } } //只有非Miss的Note才會被被撃中並消除 public override void OnKeyDown(JudgementType judgementType) { if(judgementType != JudgementType.MISS) { //加分加Combo EvaluationManager.OnHit(judgementType); //... } }
-
-
LongNoteController
-
void CheckMiss() { //沒有進入處理狀態的起點通過判定線且超過了BAD判定範圍(斷頭押) if(!isProcessed && noteProperty.secBegin - PlayerController.currentSec < -JudgementManager.judgementWidth[JudgementType.BAD]) { //起點Miss,終點也Miss EvaluationManager.OnMiss(); EvaluationManager.OnMiss(); //... } //進入了處理狀態的終點通過了判定線且超過了BAD判定範圍(Hold太久斷尾押) if(isProcessed && noteProperty.secEnd - PlayerController.currentSec < -JudgementManager.judgementWidth[JudgementType.BAD]) { EvaluationManager.OnMiss(); //... } } public override void OnKeyDown(JudgementType judgementType) { //按下時,LongNote在BAD判定範圍內 if(judgementType != JudgementType.MISS) { EvaluationManager.OnHit(judgementType); //... } } //抬手 public override void OnKeyUp(JudgementType judgementType) { //尾判評價 if(judgementType != JudgementType.MISS) { EvaluationManager.OnHit(judgementType); } else { EvaluationManager.OnMiss(); } //... }
-
-