如何从游戏引擎类向ViewController传递数据?分数传递求助
解决游戏引擎分数传递到ViewController的几种方案
Hey there! 作为刚入门的开发者,遇到跨类数据传递的问题真的太常见了,别慌,咱们一步步来搞定它~
你现在的核心需求是把nextMove()方法里的scores值传递给ViewController,用来更新Label。下面是几种iOS开发里常用且靠谱的实现方式:
方案一:用闭包(Closure)传递数据
这种方式简单直观,适合轻量的回调场景:
- 首先在你的游戏引擎类里,定义一个闭包属性,用来传递分数:
class YourGameEngineClass { // 定义闭包,参数是分数,无返回值 var onScoreUpdated: ((Int) -> Void)? // 你的其他属性和方法... private func nextMove() { current = .random(config) if (well.hasCollision(current)) { stopTimer() scene.showGameOver(scores) // 触发闭包,把分数传出去 onScoreUpdated?(scores) } else { scene.show(current) } } }
- 然后在ViewController里,初始化游戏引擎的时候绑定这个闭包:
class ViewController: UIViewController { @IBOutlet weak var scoreLabel: UILabel! let gameEngine = YourGameEngineClass() override func viewDidLoad() { super.viewDidLoad() // 绑定闭包,接收分数并更新UI gameEngine.onScoreUpdated = { [weak self] score in // UI操作必须在主线程执行! DispatchQueue.main.async { self?.scoreLabel.text = "最终分数:\(score)" } } } }
👉 注意用[weak self]避免循环引用,防止内存泄漏。
方案二:用代理(Delegate)模式
如果后续游戏引擎和ViewController还有更多交互(比如游戏暂停、重启的回调),代理模式会更清晰:
- 先定义一个代理协议:
// 定义代理协议,用AnyObject确保只能被类遵守 protocol GameEngineDelegate: AnyObject { func gameEngineDidEndGame(with score: Int) }
- 在游戏引擎类里添加代理属性:
class YourGameEngineClass { weak var delegate: GameEngineDelegate? private func nextMove() { current = .random(config) if (well.hasCollision(current)) { stopTimer() scene.showGameOver(scores) // 调用代理方法传递分数 delegate?.gameEngineDidEndGame(with: scores) } else { scene.show(current) } } }
- 让ViewController遵守这个协议,并设置代理:
class ViewController: UIViewController, GameEngineDelegate { @IBOutlet weak var scoreLabel: UILabel! let gameEngine = YourGameEngineClass() override func viewDidLoad() { super.viewDidLoad() gameEngine.delegate = self } // 实现代理方法 func gameEngineDidEndGame(with score: Int) { DispatchQueue.main.async { self.scoreLabel.text = "最终分数:\(score)" } } }
👉 代理属性一定要用weak修饰,同样是为了避免循环引用。
方案三:用单例(Singleton)存储全局分数
如果你的分数需要在多个类里访问,单例会是一个简单的选择,但要注意别滥用(单例生命周期长,可能占用不必要的内存):
- 把游戏引擎类改成单例,并添加存储分数的属性:
class YourGameEngineClass { // 单例实例 static let shared = YourGameEngineClass() // 私有化初始化方法,防止外部创建多个实例 private init() {} // 用来存储全局可访问的分数 var currentScore: Int = 0 private func nextMove() { current = .random(config) if (well.hasCollision(current)) { stopTimer() currentScore = scores // 把scores赋值给全局变量 scene.showGameOver(scores) } else { scene.show(current) } } }
- 在ViewController里直接访问这个单例的分数:
// 比如在游戏结束后获取分数 let finalScore = YourGameEngineClass.shared.currentScore scoreLabel.text = "最终分数:\(finalScore)"
小提示
- 所有UI更新操作都必须放在主线程,所以要用
DispatchQueue.main.async包裹Label的赋值代码; - 优先推荐闭包或代理模式,单例适合简单场景,复杂项目里尽量少用,避免代码耦合度太高。
内容的提问来源于stack exchange,提问作者Bilal Şimşek
相关产品推荐
相关产品推荐

