Unity中通用Timer类的方法调用时机选择疑问
问题解答
核心原则:单一职责与通用性
既然Timer是通用脚本,不能和任何场景、UI绑定,那计时的核心逻辑(数值递减)必须放在Timer内部的Update里,SumoController只负责读取Timer的数值、更新UI以及触发游戏状态变更即可。
具体实现方案
1. 优化Timer类
保留Timer自身的Update处理计时逻辑,同时把内部计时字段设为私有,通过只读属性对外暴露,避免外部直接修改数值,保证封装性:
using UnityEngine; public class Timer : MonoBehaviour { [SerializeField] private float _startCountdown = 5f; [SerializeField] private float _endCountdown = 300f; // 提供只读属性供外部访问计时数值 public float StartCountdown => _startCountdown; public float EndCountdown => _endCountdown; private void Update() { UpdateStartTimer(); UpdateEndTimer(); } // 内部私有方法处理计时递减逻辑 private void UpdateStartTimer() { if (_startCountdown >= 0f) { _startCountdown -= Time.deltaTime; } } private void UpdateEndTimer() { if (_endCountdown >= 0f) { _endCountdown -= Time.deltaTime; } } // 可选:增加重置计时器的方法,提升通用性 public void ResetStartTimer(float newValue = 5f) { _startCountdown = newValue; } public void ResetEndTimer(float newValue = 300f) { _endCountdown = newValue; } }
2. 优化SumoController类
移除SumoController中重复的计时逻辑,只保留UI更新和游戏状态控制的职责:
using UnityEngine; public class SumoController : MonoBehaviour { public bool isWin; public bool isGameOver; public bool isGameStart; public SumoTankController player; public SumoTankAI bot; public SumoUIManager sumoUIManager; public Timer timer; private void Start() { player.sumoController = this; player.GetComponentInChildren<SumoTankGun>().sumoController = this; bot.sumoController = this; bot.GetComponentInChildren<SumoTankAIGun>().sumoController = this; sumoUIManager.matchResultText.gameObject.SetActive(false); sumoUIManager.timeToStartGame.gameObject.SetActive(true); } private void Update() { UpdateStartGameUI(); UpdateEndGameUI(); } public void CheckMatchResult() { if (isGameOver) return; sumoUIManager.matchResultText.text = isWin ? "Вы победили!" : "Вы проиграли!"; sumoUIManager.matchResultText.gameObject.SetActive(true); isGameOver = true; } private void UpdateStartGameUI() { if (timer.StartCountdown >= 0f) { sumoUIManager.timeToStartGame.text = $"{timer.StartCountdown:f1}"; } else if (!isGameStart) { sumoUIManager.timeToStartGame.gameObject.SetActive(false); isGameStart = true; } } private void UpdateEndGameUI() { if (timer.EndCountdown >= 0f) { int minutes = Mathf.FloorToInt(timer.EndCountdown / 60); int seconds = Mathf.FloorToInt(timer.EndCountdown % 60); sumoUIManager.timeToEndGame.text = $"{minutes:00}:{seconds:00}"; } else if (!isGameOver) { sumoUIManager.backBtn.onClick.Invoke(); isGameOver = true; } } }
方案优势
- 保证Timer通用性:Timer只专注于计时逻辑,不依赖任何场景或UI,可直接在其他项目中复用。
- 遵循单一职责:SumoController只处理游戏流程和UI更新,职责清晰,代码更易维护。
- 提升封装性:Timer的内部数值通过只读属性暴露,避免外部误修改导致的逻辑错误。
内容的提问来源于stack exchange,提问作者Hatemsla
相关产品推荐
相关产品推荐

