如何禁用SpriteKit节点触摸事件并25秒后启用以跳转至下一场景
解决SpriteKit按钮全程可见但前25秒禁用交互的问题
Hey there! 针对你在GameScene里的需求——播放25秒音频期间按钮全程可见但无法点击,音频结束后允许点击跳转——我给你两个实用的解决方案,完美适配你的场景:
方案一:用定时器精准控制交互状态
这个方案简单直接,适合你已经明确音频时长是25秒的情况:
- 初始化按钮状态:在场景加载时,先把按钮设为可见但禁用交互
- 启动定时器:播放音频的同时,设置一个25秒的定时器,时间到后启用按钮交互
代码示例:
override func didMove(to view: SKView) { // 确保按钮全程可见 nextButton.isHidden = false // 初始状态禁用触摸交互 nextButton.isUserInteractionEnabled = false // 可选:给禁用状态加视觉提示,比如半透明 nextButton.alpha = 0.6 // 播放你的25秒音频 playGameAudio() // 25秒后启用按钮交互 Timer.scheduledTimer(withTimeInterval: 25.0, repeats: false) { [weak self] _ in guard let self = self else { return } self.nextButton.isUserInteractionEnabled = true // 恢复按钮视觉状态,提示用户可点击 self.nextButton.run(SKAction.group([ SKAction.fadeAlpha(to: 1.0, duration: 0.3), SKAction.scale(to: 1.1, duration: 0.2).reversed() // 轻微缩放动画 ])) } } // 处理触摸事件 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first else { return } let location = touch.location(in: self) // 只需判断按钮是否包含触摸点,且交互已启用 if nextButton.contains(location) && nextButton.isUserInteractionEnabled { goToScene(scene: getNextScene()!) } }
方案二:监听音频播放完成事件(更可靠)
如果担心定时器和实际音频播放时长有偏差(比如音频加载延迟、格式问题导致时长波动),可以直接监听音频播放完成的回调,这种方式更准确:
代码示例(以AVAudioPlayer为例):
import AVFoundation class GameScene: SKScene, AVAudioPlayerDelegate { var audioPlayer: AVAudioPlayer? var nextButton: SKNode! // 你的按钮节点 override func didMove(to view: SKView) { nextButton.isHidden = false nextButton.isUserInteractionEnabled = false nextButton.alpha = 0.6 // 加载并播放音频 guard let audioURL = Bundle.main.url(forResource: "game_audio", withExtension: "mp3") else { print("找不到音频文件") return } do { audioPlayer = try AVAudioPlayer(contentsOf: audioURL) audioPlayer?.delegate = self audioPlayer?.play() } catch { print("音频初始化失败:\(error.localizedDescription)") } } // 音频播放完成时触发 func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { if flag { nextButton.isUserInteractionEnabled = true nextButton.run(SKAction.fadeAlpha(to: 1.0, duration: 0.3)) } } // 触摸事件处理和方案一一致 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first else { return } let location = touch.location(in: self) if nextButton.contains(location) && nextButton.isUserInteractionEnabled { goToScene(scene: getNextScene()!) } } }
小提示
- 视觉反馈很重要:禁用时给按钮加半透明、灰色调,启用时恢复正常状态,甚至加个小动画,用户能更清晰地感知按钮状态
- 使用
[weak self]避免循环引用:定时器和音频代理的闭包里一定要用弱引用,防止内存泄漏
内容的提问来源于stack exchange,提问作者Jen
相关产品推荐
相关产品推荐

