Unity快艇竞速游戏最佳圈计时不更新问题求助
最佳圈计时功能修复方案
核心问题分析
- 第一圈逻辑错误:初始
bestHour/bestMinute/bestSecond默认值为0,第一圈完成时的判断逻辑冗余,且未在第一圈结束后切换isFirstLap状态,导致后续圈无法进入正确的时间比较分支。 - 非第一圈比较逻辑漏洞:单独拆分小时、分钟、秒进行比较的方式不严谨,无法准确判断总时长是否更短;同时存在笔误——
currentMinute = currentMinute完全无效,未对bestMinute赋值。 - TimerFunction重复调用:
OnTriggerEnter中两个条件都会触发计时逻辑,导致时间计算混乱。 - 时间重置与状态重置缺失:当前代码未在圈数完成后重置
isCalled,影响下一圈的冲线判断;时间进位逻辑使用==判断,易因浮点精度问题跳过进位。
修复步骤
1. 统一时间比较逻辑
将当前时间和最佳时间转换为总秒数进行比较,避免分单位比较的逻辑漏洞,确保判断结果准确。
2. 修正第一圈状态切换
第一圈完成后立即将isFirstLap设为false,确保后续圈进入正确的时间比较分支。
3. 清理重复触发逻辑
移除OnTriggerEnter中重复调用TimerFunction的代码,确保每圈仅触发一次计时更新。
4. 优化时间进位与初始化
将最佳时间初始化为极大值,保证第一圈必然更新;时间进位时改用减法替代直接重置,避免精度丢失;用>=替代==判断进位条件。
修改后的完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine.UI; using UnityEngine; public class Race_Manager : MonoBehaviour { [HideInInspector] public bool enter = false; [HideInInspector] public bool isCalled = true; [HideInInspector] public bool lapCompleted = false; [HideInInspector] public bool raceStarted = false; [HideInInspector] public float currentHour; [HideInInspector] public float currentMinute; [HideInInspector] public float currentSecond; [HideInInspector] public float bestHour; [HideInInspector] public float bestMinute; [HideInInspector] public float bestSecond; public float timerSpeed = 10f; [HideInInspector] public int lapsDone; public int lapsToDo = 5; [HideInInspector] public int pointsHit; [HideInInspector] public Race_Checkpoint[] checkpoints; public Text currentTimeCounter; public Text bestTimeCounter; public Text lapCounter; public Canvas normalUI; public Canvas completionUI; public AudioSource successMusic; private bool raceOver = false; private CarCameras carCamera; private GameObject playerCar; private bool mainFunctionCalled = false; private bool timerActivated = false; private bool isFirstLap = true; void Start () { playerCar = GameObject.FindWithTag ("Player"); carCamera = GameObject.FindObjectOfType<CarCameras> (); checkpoints = GetComponentsInChildren<Race_Checkpoint> (); // 初始化最佳时间为极大值,确保第一圈必然更新 bestHour = 99; bestMinute = 59; bestSecond = 59; } void Update () { lapCounter.text = string.Format("Laps: {0} / {1}", lapsDone, lapsToDo); currentTimeCounter.text = string.Format("Current Time: {0:00}:{1:00}:{2:00}", currentHour, currentMinute, currentSecond); bestTimeCounter.text = string.Format("Best Time: {0:00}:{1:00}:{2:00}", bestHour, bestMinute, bestSecond); if (raceOver == true && mainFunctionCalled == true) { StartCoroutine (WinFunction()); } if (raceOver == true) { playerCar.GetComponent<CarController> ().handbrakeInput = 1f; } if (timerActivated == true) { currentSecond += Time.deltaTime * timerSpeed; } if (currentSecond > 60f) { currentSecond -= 60f; // 用减法替代重置,避免精度丢失 currentMinute += 1f; } if (currentMinute >= 60f) { // 用>=替代==,避免浮点精度问题 currentMinute -= 60f; currentHour += 1f; } if (enter == true) { foreach (Race_Checkpoint point in checkpoints) point.ResetPoint (); } } void OnTriggerEnter (Collider other) { if (other.transform.parent.transform.parent.transform.tag == "Player" && raceStarted == false && lapsDone == 0 && isCalled == true) { timerActivated = true; raceStarted = true; lapsDone += 1; isCalled = false; enter = true; } else if (other.transform.parent.transform.parent.transform.tag == "Player" && raceStarted == true && isCalled == true && lapCompleted) { lapCompleted = false; isCalled = false; lapsDone += 1; pointsHit = 0; enter = true; // 仅在此处调用计时更新,避免重复触发 StartCoroutine (TimerFunction ()); } else { enter = false; } if (enter == true && lapsDone == lapsToDo + 1) { mainFunctionCalled = true; raceOver = true; } } IEnumerator WinFunction() { yield return new WaitForSeconds (0f); RestartGame restarter = GetComponent<RestartGame> (); successMusic.Play (); raceOver = true; normalUI.gameObject.SetActive (false); completionUI.gameObject.SetActive(true); playerCar.GetComponent<CarController> ().handbrakeInput = 1f; playerCar.GetComponent<CarController> ().throttleInput = 0f; playerCar.GetComponent<CarController> ().steerInput = 0f; playerCar.GetComponent<CarDynamics> ().controller = CarDynamics.Controller.external; carCamera.GetComponent<CarCameras> ().enabled = false; carCamera.GetComponent<CarCamerasController> ().enabled = false; carCamera.GetComponent<Animation> ().Play ("Camera_Finish"); timerActivated = false; mainFunctionCalled = false; if (restarter != null) { restarter.enabled = false; } } IEnumerator TimerFunction() { yield return null; // 等待一帧确保时间数据稳定 // 转换为总秒数进行比较 float currentTotalSeconds = currentHour * 3600 + currentMinute * 60 + currentSecond; float bestTotalSeconds = bestHour * 3600 + bestMinute * 60 + bestSecond; if (isFirstLap) { // 第一圈直接赋值为最佳时间 bestHour = currentHour; bestMinute = currentMinute; bestSecond = currentSecond; isFirstLap = false; // 切换状态 } else if (currentTotalSeconds < bestTotalSeconds) { // 当前圈时间更短,更新最佳时间 bestHour = currentHour; bestMinute = currentMinute; bestSecond = currentSecond; } // 重置当前圈计时与触发状态 currentHour = 0f; currentMinute = 0f; currentSecond = 0f; isCalled = true; } }
额外优化说明
- 初始最佳时间设为99:59:59,确保第一圈完成后必然更新最佳记录。
- 时间进位采用减法逻辑,避免直接重置为0导致的浮点精度丢失。
- 在
TimerFunction末尾重置isCalled,保证下一圈能正常触发冲线判断。
内容的提问来源于stack exchange,提问作者LukeyC116
相关产品推荐
相关产品推荐

