這一個遊戲已經大致上完成差不多了,今天就開始製作分數系統。
原本的遊戲主要是以存活時間為主,但如果只有一直躲避障礙物,玩家可能比較難感受到自己的遊玩成果,所以這次加入分數計算,讓玩家可以在遊戲過程中看到目前的分數,死亡後也能留下最高紀錄。
這次的分數主要會根據遊玩時間與目前遊戲速度來計算,讓遊戲後期速度越快時,分數增加也會越快。
首先製作一個 ScoreManager,負責計算和顯示目前分數。
我設定基礎每秒增加 10 分,再透過前幾天製作好的RockSpawner取得目前遊戲速度,計算現在的速度倍率。
例如遊戲初始速度是 4:
速度 4.0 → 1 倍分數
速度 4.8 → 1.2 倍分數
速度 5.6 → 1.4 倍分數
速度 6.4 → 1.6 倍分數
速度 7.2 → 1.8 倍分數
速度 8.0 → 2 倍分數
這樣遊戲隨著時間逐漸加速時,分數也會跟著增加得更快。
這次的ScoreManager如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro; // 若使用 TextMeshPro 請保留,若用傳統 Text 改成 UnityEngine.UI
public class ScoreManager : MonoBehaviour
{
public static ScoreManager Instance;
[Header("UI 顯示元件")]
[Tooltip("顯示當前分數的 TextMeshPro 元件")]
public TMP_Text scoreText;
[Tooltip("遊戲結束時顯示最佳紀錄的 TextMeshPro 元件")]
public TMP_Text highScoreText;
[Header("分數計算設定")]
[Tooltip("基礎每秒增加的分數點數")]
public float pointsPerSecond = 10f;
[Tooltip("初始基礎速度(用來計算加速時的分數倍率)")]
public float baseSpeedReference = 4f;
private float currentScoreRaw = 0f; // 內部精確累加的浮點數分數
private bool isScoring = false;
private RockSpawner rockSpawner;
void Awake()
{
if (Instance == null) Instance = this;
else Destroy(gameObject);
}
void Start()
{
rockSpawner = FindObjectOfType<RockSpawner>();
StartScoring();
}
void Update()
{
if (!isScoring) return;
// 取得當前場景速度(開技能時會是最高速度 8f,平時隨時間提速)
float currentSpeed = (rockSpawner != null) ? rockSpawner.GetCurrentSpeed() : baseSpeedReference;
// 速度倍率:當前的速度是初始速度的幾倍(例如:8 / 4 = 2 倍速,分數也增長 2 倍)
float speedMultiplier = currentSpeed / baseSpeedReference;
// 累加分數:時間 * 基礎分 * 速度倍率
currentScoreRaw += Time.deltaTime * pointsPerSecond * speedMultiplier;
// 更新 UI 顯示
UpdateScoreUI();
}
void UpdateScoreUI()
{
if (scoreText == null) return;
// 【核心視覺魔法】
// 將內部浮點數乘以 100 後取整數,後兩位就會因為每幀微小跳動而呈現「亂碼般快速飆升」的感覺!
int displayScore = Mathf.FloorToInt(currentScoreRaw * 100f);
// 格式化為 6 位數,前面補 0(例如:001428)
scoreText.text = displayScore.ToString("D6");
}
public void StartScoring()
{
isScoring = true;
}
public void StopScoring()
{
isScoring = false;
SaveHighScore();
}
// 取得最後結算分數(可供結算畫面讀取)
public int GetFinalScore()
{
return Mathf.FloorToInt(currentScoreRaw * 100f);
}
// 保存與刷新高分紀錄
private void SaveHighScore()
{
int finalScore = GetFinalScore();
int savedHighScore = PlayerPrefs.GetInt("HighScore", 0);
if (finalScore > savedHighScore)
{
savedHighScore = finalScore;
PlayerPrefs.SetInt("HighScore", savedHighScore);
PlayerPrefs.Save();
}
if (highScoreText != null)
{
highScoreText.text = "BEST: " + savedHighScore.ToString("D6");
}
}
}
這次主要利用currentScoreRaw累積分數,再透過speedMultiplier讓分數和遊戲速度產生關聯。
另外顯示分數時會乘上 100,再使用六位數格式顯示,例如:
000125
001428
012560
讓分數在遊戲中可以持續快速增加。
分數不能在小鳥死亡後繼續增加,所以在原本的 Die() 裡加入停止計分的功能。
void Die()
{
isDead = true;
Debug.Log("小鳥撞到了!遊戲結束。");
// 【新增】死亡時停止計分並結算保存高分紀錄
if (ScoreManager.Instance != null)
{
ScoreManager.Instance.StopScoring();
}
}
當小鳥撞到岩石或地面後,就會停止計分,並進行最後的分數結算。
遊戲結束後會將這次的分數與之前保存的最高分比較。如果這次分數比較高,就使用PlayerPrefs保存新的最高分,這樣即使重新開始遊戲,也可以保留之前的最佳紀錄。
目前的流程就是:
遊戲開始→開始計分→遊戲速度增加→分數增加速度也提高→小鳥死亡→停止計分→計算最終分數→與最高分比較→保存BEST
今天大致完成這遊戲了,之後應該會從下一個小遊戲著手開始製作,畢竟開一個網頁只放一個遊戲感覺有一點單調,接下來這14天應該會再製作下一個小遊戲,目前就三個想法,小朋友下樓梯、打地鼠、打飛機三種遊戲做選擇。