Kotlin实现按钮指令匹配胜率计数功能代码异常求解
原有代码的核心问题
- 语法错误:Kotlin中
if/else不加大括号时,仅对紧随其后的第一行代码生效。你写的判断逻辑里,counter +=20、发送下一条指令的代码根本不在匹配成功的分支内,else也只会匹配到最内层的if,分支逻辑完全错乱。 - 逻辑缺陷:用固定
delay(3000)傻等3秒,完全没有监听「按住中途松手」「按错其他按钮」的异常场景,也没有做状态记录,根本无法判断用户是不是真的按住正确按钮满了时长。 - 结构问题:硬编码嵌套四层按钮判断,扩展性极差,错误后重启的逻辑没有闭环,也没有实现顺序解锁(x→y→z→w)的状态管理,计数规则也没落地。
- 协程使用错误:直接用
GlobalScope启动协程没有结构化并发约束,容易内存泄漏,也没法在出错时取消无效的等待任务。
实现思路
- 把四个按钮按解锁顺序存在列表里,用一个索引变量记录当前需要验证的关卡,不用硬写嵌套判断,出错重置索引即可回到x按钮的初始环节。
- 单独维护按压状态:监听按钮的按下、松开两个事件,按下时先校验是否匹配当前指令按钮,匹配才开始计时,不匹配直接触发重置。
- 计时过程中持续校验按压状态:只要中途松开、或者按了别的按钮,立刻取消计时、计数器归零、回到初始关卡。
- 按住满3秒后才给计数器加20,进入下一关,发送对应按钮的操作提示。
参考实现代码
import kotlinx.coroutines.* // 按验证顺序定义按钮标签 private val buttonOrder = listOf("x", "y", "z", "w") private var currentStep = 0 var counter = 0 // 保存计时任务,出错/切换关卡时可以直接取消 private var countDownJob: Job? = null // 实际项目中替换为页面/业务自身的协程作用域,禁止直接使用GlobalScope private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob()) /** * 发送操作提示,保留原有函数结构,实际场景中可在这里更新UI提示用户 */ fun sendInstruction(buttonLabel: String): String { println("请按住按钮 $buttonLabel 保持3秒") return buttonLabel } /** * 按钮按下事件回调,在按钮的按下监听里调用 * @param pressedLabel 用户按下的按钮标签 */ fun onButtonPress(pressedLabel: String) { // 先取消上一轮没完成的计时任务 countDownJob?.cancel() val targetLabel = buttonOrder[currentStep] if (pressedLabel != targetLabel) { // 按错按钮,直接重置流程 resetFlow() return } // 按对当前按钮,开始3秒计时校验 countDownJob = scope.launch { var heldTime = 0L val checkInterval = 100L while (heldTime < 3000) { delay(checkInterval) heldTime += checkInterval // 每次轮询校验用户是否持续按住正确按钮,实际项目替换为自己的按压状态判断逻辑 if (!isUserHoldingButton(pressedLabel)) { resetFlow() return@launch } } // 按住满3秒,验证通过 counter += 20 currentStep++ if (currentStep >= buttonOrder.size) { println("全部按钮验证通过,当前得分:$counter") return@launch } // 发送下一个按钮的操作指令 sendInstruction(buttonOrder[currentStep]) } } /** * 按钮松开事件回调,在按钮的松开监听里调用 */ fun onButtonRelease() { // 计时未完成就松开按钮,直接重置流程 if (countDownJob?.isActive == true) { resetFlow() } } /** * 重置流程:计数器归零,回到x按钮验证环节 */ fun resetFlow() { countDownJob?.cancel() counter = 0 currentStep = 0 sendInstruction(buttonOrder[currentStep]) } // 示例方法,实际项目替换为你自己的按压状态判断逻辑 fun isUserHoldingButton(label: String): Boolean { return true } // 业务初始化时调用,启动第一个验证指令 fun initFlow() { resetFlow() }
补充说明
- 代码没有用固定
delay(3000)等待,而是每隔100ms检查一次按压状态,只要中途松手、按错键都会立刻触发重置,符合校验逻辑要求。 - 所有状态统一管理,不管在哪一步出错都直接调用
resetFlow()回到初始状态,不用写重复的重启逻辑。 - 协程用结构化作用域管理,计时任务可随时取消,不会出现内存泄漏、无效等待的问题。
- 如果要落地「不匹配则计数器递减」的胜率统计逻辑,只需要在按错分支、中途松手分支的重置逻辑前,加上
counter = (counter - 1).coerceAtLeast(0)即可,避免计数器出现负数。
内容的提问来源于stack exchange,提问作者EMT
相关产品推荐
相关产品推荐

