You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift游戏开发:GameScene无法调用ViewController的updateScore函数问题

问题排查与解决方案

核心问题:viewController 为 nil,导致可选链调用失败

GameScene 里的 viewController?.updateScore(...) 使用了可选链,当 viewController 是 nil 时,后续代码不会执行——这就是你看不到打印输出的直接原因。以下是具体问题点和修复步骤:


1. 正确声明 GameScene 的 viewController 属性

GameScene 必须先定义 viewController 可选属性,且要用 weak 修饰避免循环引用(ViewController 持有 GameScene,若 GameScene 强引用 ViewController 会导致内存泄漏):

class GameScene: SKScene {
    weak var viewController: ViewController? // 关键:声明弱引用可选属性
    var score = 0 // 游戏内的分数变量
    
    // 分数增长逻辑示例
    func increaseScore() {
        score += 1
        updateViewScore()
    }
    
    func updateViewScore() {
        // 传递实际的score值,而非固定的10
        viewController?.updateScore(score: score)
    }
}

2. 修正 ViewController 中 GameScene 的初始化逻辑

不能在类的顶层直接初始化 gameScene(此时 view.bounds 还未完成初始化),必须放在视图生命周期方法(如 viewDidLoad)中,同时要将 GameScene 展示到 SKView 上:

class ViewController: UIViewController {
    var gameScene: GameScene!
    var score = 0 // ViewController侧的分数变量
    var interstitial: GADInterstitial? // 你的插屏广告变量
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 初始化GameScene
        gameScene = GameScene(size: view.bounds.size)
        gameScene.viewController = self
        
        // 将GameScene展示到SKView(这步极易遗漏)
        guard let skView = view as? SKView else {
            print("当前视图不是SKView")
            return
        }
        skView.presentScene(gameScene)
    }
    
    func updateScore(score: Int) {
        print("updateScore was called with score: \(score)")
        self.score = score // 更新ViewController侧的分数
        popUp(with: score)
    }
    
    // 移除@IBAction,改为普通方法(代码调用而非按钮触发)
    func popUp(with score: Int) {
        if score % 10 == 0 {
            // 增加广告就绪判断,避免未就绪时调用
            if interstitial != nil && interstitial!.isReady {
                interstitial?.present(fromRootViewController: self)
                // 广告展示后重新加载,保证下一次触发时有可用广告
                interstitial = createNewInterstitial()
            } else {
                print("Ad wasn't ready")
            }
        }
    }
    
    // 辅助方法:创建新的插屏广告(示例)
    func createNewInterstitial() -> GADInterstitial {
        let interstitial = GADInterstitial(adUnitID: "你的广告ID")
        interstitial.load(GADRequest())
        return interstitial
    }
}

3. 广告触发逻辑优化

  • 原 popUp 是 @IBAction,适合按钮触发场景,代码调用时改为普通方法更合理
  • 增加 isReady 判断,确保广告就绪后再展示
  • 广告展示后重新加载,保证后续触发时有可用广告

内容的提问来源于stack exchange,提问作者Sider the Programmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 23:03:32