Unity长按按键时持续消耗Stamina的实现问题求助
解决Unity长按按键持续消耗耐力(Stamina)的冻结问题
问题根源
你遇到的冻结是因为协程中无暂停的循环会阻塞主线程,另外你对按键检测的理解有误——Update是每帧执行的,完全可以用来检测按键的长按状态,之前的单次触发逻辑不适合持续消耗场景。
解决方案
我们需要:
- 在
Update中检测按键的按住状态,启动/停止持续消耗的协程 - 用带暂停的协程实现平滑的耐力持续减少
- 确保消耗与回复逻辑互斥,避免冲突
修改后的完整代码
using System.Collections; using UnityEngine; using UnityEngine.UI; public class Stamina : MonoBehaviour { public Slider staminaBar; private int maxStamina = 100; private int currentStamina; public static Stamina instance; // 耐力消耗与回复的时间间隔(控制平滑度) private WaitForSeconds consumeTick = new WaitForSeconds(0.1f); private WaitForSeconds regenTick = new WaitForSeconds(0.1f); // 记录当前的消耗/回复协程,防止重复启动 private Coroutine activeConsumeCoroutine; private Coroutine activeRegenCoroutine; private void Awake() { instance = this; } void Start() { currentStamina = maxStamina; staminaBar.maxValue = maxStamina; staminaBar.value = maxStamina; } void Update() { // 检测Shift键长按:按住时启动消耗协程,松开时停止 if (Input.GetKey(KeyCode.LeftShift)) { if (activeConsumeCoroutine == null && currentStamina > 0) { activeConsumeCoroutine = StartCoroutine(ConsumeStaminaOverTime(5)); } } else { if (activeConsumeCoroutine != null) { StopCoroutine(activeConsumeCoroutine); activeConsumeCoroutine = null; // 停止消耗后启动回复协程 StartRegenStamina(); } } } // 持续消耗耐力的协程 private IEnumerator ConsumeStaminaOverTime(int amountPerTick) { while (currentStamina > 0) { currentStamina -= amountPerTick; // 防止耐力低于0 currentStamina = Mathf.Max(currentStamina, 0); staminaBar.value = currentStamina; // 每0.1秒扣一次,保证主线程不阻塞 yield return consumeTick; } activeConsumeCoroutine = null; Debug.Log("耐力耗尽!"); // 耗尽后停止消耗,启动回复 StartRegenStamina(); } // 启动耐力回复(带延迟) private void StartRegenStamina() { if (activeRegenCoroutine != null) { StopCoroutine(activeRegenCoroutine); } activeRegenCoroutine = StartCoroutine(RegenStamina()); } private IEnumerator RegenStamina() { // 回复前的延迟 yield return new WaitForSeconds(2); while (currentStamina < maxStamina) { // 每次回复1点(或按比例调整) currentStamina += maxStamina / 100; currentStamina = Mathf.Min(currentStamina, maxStamina); staminaBar.value = currentStamina; yield return regenTick; } activeRegenCoroutine = null; } }
关键修改点说明
- 按键检测逻辑:移到
Update中,通过Input.GetKey检测长按状态,GetKey会在按键按住的每帧返回true,完美适配持续消耗场景 - 持续消耗协程:
ConsumeStaminaOverTime中每0.1秒扣一次耐力,通过yield return让主线程有时间处理其他逻辑,彻底解决冻结问题 - 协程管理:用
activeConsumeCoroutine和activeRegenCoroutine记录当前运行的协程,防止重复启动导致的逻辑混乱 - 边界处理:添加
Mathf.Max和Mathf.Min保证耐力值不会超出0~max的范围
内容的提问来源于stack exchange,提问作者dumprogramor
相关产品推荐
相关产品推荐

