Swift 如何从GameViewController更新SKScene中的变量?

Swift 如何从GameViewController更新SKScene中的变量?,swift,sprite-kit,Swift,Sprite Kit,我已将admob奖励视频添加到我的应用程序中。admob一切正常。但是,我看了视频后无法更新live标签。如果我转到另一个场景并返回,它将更新并显示新的值 //GameViewController.swift func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd, didRewardUserWith reward: GADAdReward) {

我已将admob奖励视频添加到我的应用程序中。admob一切正常。但是,我看了视频后无法更新live标签。如果我转到另一个场景并返回,它将更新并显示新的值

//GameViewController.swift

 func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd,
                            didRewardUserWith reward: GADAdReward) {
        print("Reward received with currency: \(reward.type), amount \(reward.amount).")


        GameData.shared.lives = GameData.shared.lives + 1
        UserDefaults.standard.set(GameData.shared.lives, forKey: "lives")
        UserDefaults.standard.synchronize()
    }
//斯威夫特

var lives = UserDefaults.standard.integer(forKey: "lives") {
        didSet{
            livesLabel?.text = "\(lives)"
        }
    }

//有几种方法可以做到这一点

您可以设置在值更改时触发通知和观察者,然后相应地调整标签

您可以使用协议,但我认为这对于本例来说过于复杂

最简单的方法可能是从实例化开始,将
mainsecene
的变量存储在GameViewController中

private var mainScene: MainScene!

// Load the SKScene from MainScene.sks'
mainScene = MainScene(fileNamed: "MainScene")
mainScene.scaleMode = .aspectFill
self.view?.presentScene(mainScene, transition)
如果没有在场景编辑器中创建相应的SKS文件,而是通过代码加载场景,请使用

//load the mainScene using init created in code
mainScene = MainScene(size: self.view?.bounds.size)
mainScene.scaleMode = .aspectFill
self.view?.presentScene(mainScene, transition)
现在,当您想从GameViewController引用该场景时,只需使用

GameData.shared.lives += 1
mainScene.lives = GameData.shared.lives

有几种方法可以做到这一点

您可以设置在值更改时触发通知和观察者,然后相应地调整标签

您可以使用协议,但我认为这对于本例来说过于复杂

最简单的方法可能是从实例化开始,将
mainsecene
的变量存储在GameViewController中

private var mainScene: MainScene!

// Load the SKScene from MainScene.sks'
mainScene = MainScene(fileNamed: "MainScene")
mainScene.scaleMode = .aspectFill
self.view?.presentScene(mainScene, transition)
如果没有在场景编辑器中创建相应的SKS文件,而是通过代码加载场景,请使用

//load the mainScene using init created in code
mainScene = MainScene(size: self.view?.bounds.size)
mainScene.scaleMode = .aspectFill
self.view?.presentScene(mainScene, transition)
现在,当您想从GameViewController引用该场景时,只需使用

GameData.shared.lives += 1
mainScene.lives = GameData.shared.lives

我个人的建议是通过计算属性与场景建立连接:

class ViewController : UIViewController
{
    var mainScene : MainScene? { return (self.view as SKView?).scene as? MainScene}
    var lives : Int
    {
        get
        {
            return mainScene?.lives ?? 0
        }
        set
        {
           mainScene?.lives = newValue
           //perhaps do some error handling if mainscne is nil
        }
   }
}
然后在主场景中,您可以控制Lifes如何写入UserDefault

class MainScene : SKScene
{
    private var _lives : Int?
    var lives : Int
    {
        get
        {
            _lives = _lives ?? UserDefaults.standard.integer(forKey: "lives")
            return _lives!
        }
        set
        {
            _lives = newValue
            UserDefaults.standard.set(_lives, forKey: "lives")
            UserDefaults.standard.synchronize()
            livesLabel?.text = "\(_lives)"
        }
    }
}
最后,要使用它,您需要执行以下操作:

 func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd,
                        didRewardUserWith reward: GADAdReward) {
    print("Reward received with currency: \(reward.type), amount \(reward.amount).")

    lives += 1
}

然后,我们可以避免处理全局变量,这意味着错误和bug的机会更少

我个人的建议是通过计算属性与场景建立连接:

class ViewController : UIViewController
{
    var mainScene : MainScene? { return (self.view as SKView?).scene as? MainScene}
    var lives : Int
    {
        get
        {
            return mainScene?.lives ?? 0
        }
        set
        {
           mainScene?.lives = newValue
           //perhaps do some error handling if mainscne is nil
        }
   }
}
然后在主场景中,您可以控制Lifes如何写入UserDefault

class MainScene : SKScene
{
    private var _lives : Int?
    var lives : Int
    {
        get
        {
            _lives = _lives ?? UserDefaults.standard.integer(forKey: "lives")
            return _lives!
        }
        set
        {
            _lives = newValue
            UserDefaults.standard.set(_lives, forKey: "lives")
            UserDefaults.standard.synchronize()
            livesLabel?.text = "\(_lives)"
        }
    }
}
最后,要使用它,您需要执行以下操作:

 func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd,
                        didRewardUserWith reward: GADAdReward) {
    print("Reward received with currency: \(reward.type), amount \(reward.amount).")

    lives += 1
}

这样我们就可以避免处理全局变量,这意味着错误和bug的机会减少了

嗨,Ron,它不起作用了。也许是因为奖励视频是从主场景开始的。因此,主场景已经加载。从哪里开始并不重要。我会在mainsecene.lives行上设置一个断点,并检查变量是否确实是您正在运行的场景Hi Ron,它不起作用。也许是因为奖励视频是从主场景开始的。因此,主场景已经加载。从哪里开始并不重要。我会在Main Scene.lives行上放置一个断点,并检查变量是否确实是您正在运行的场景我有一个问题:“GameViewController”类型的值没有成员“scenemy error,忘记指向视图,我有一个问题:类型为“GameViewController”的值没有成员“scenemy Error,忘记指向视图,但这也是您应该注意的。