LibGDX中如何在for循环内实现延迟执行效果?
LibGDX 实现Simon Says按钮序列播放的解决方案
原有代码问题分析
原有代码无法实现预期效果,核心问题有两点:
- 循环中所有定时任务的延迟参数完全相同,循环执行耗时极短,所有按钮会几乎同时触发状态切换,没有按顺序播放的效果
- LibGDX的
Timer默认在后台线程执行任务,直接在任务中修改按钮UI属于跨线程操作,存在线程安全风险,可能出现画面闪烁、操作无响应等异常
方案1:修正Timer调度逻辑(快速实现)
调整每个任务的延迟时间,实现按顺序亮灭,同时将UI操作抛到LibGDX的GL渲染线程执行,避免线程安全问题:
val stepDelay = 1f // 单个按钮的亮灯时长,单位秒 val gapDelay = 0.3f // 两个按钮亮灯之间的间隔时长,单位秒 for (i in 0 until array.size) { // 计算当前按钮的点亮、熄灭时间点 val lightOnTime = i * (stepDelay + gapDelay) val lightOffTime = lightOnTime + stepDelay // 调度点亮任务 Timer.schedule(object : Timer.Task() { override fun run() { // 把UI操作抛到渲染线程执行 Gdx.app.postRunnable { array[i].toggle() } } }, lightOnTime) // 调度熄灭任务 Timer.schedule(object : Timer.Task() { override fun run() { Gdx.app.postRunnable { array[i].toggle() } } }, lightOffTime) }
方案2:自定义序列控制器(更稳定可控)
游戏场景更推荐该方案,完全在渲染线程执行,没有线程安全问题,还可以自由控制暂停、重播、快进等操作:
首先定义序列控制器类:
class SimonSequencePlayer( private val buttons: List<Button>, // 你的按钮数组 private val stepDelay: Float = 1f, private val gapDelay: Float = 0.3f ) { private var isPlaying = false private var elapsedTime = 0f private var currentStep = 0 private var isLightOn = false // 当前步骤的按钮是否处于亮灯状态 fun startPlay() { isPlaying = true elapsedTime = 0f currentStep = 0 isLightOn = false } // 在render方法中每帧调用,传入delta时间 fun update(delta: Float) { if (!isPlaying || currentStep >= buttons.size) return elapsedTime += delta val targetDuration = if (isLightOn) stepDelay else gapDelay if (elapsedTime >= targetDuration) { elapsedTime -= targetDuration if (isLightOn) { // 熄灭当前按钮 buttons[currentStep].toggle() currentStep++ isLightOn = false // 所有步骤播放完成 if (currentStep >= buttons.size) { isPlaying = false } } else { // 点亮下一个按钮 buttons[currentStep].toggle() isLightOn = true } } } }
使用方式:
- 初始化控制器实例
val player = SimonSequencePlayer(buttonArray) - 需要播放序列时调用
player.startPlay() - 在游戏的
render()方法中每帧调用player.update(Gdx.graphics.deltaTime)即可
内容的提问来源于stack exchange,提问作者Tururu Tururu
相关产品推荐
相关产品推荐

