【问题标题】:GKState: Why is StateMachine == nil on delegate call?GKState:为什么 StateMachine == nil 代表调用?
【发布时间】:2019-04-21 07:17:09
【问题描述】:

我正在使用 GKStateMachine 开发一个 SpriteKit 游戏,用于在多个场景之间进行转换。我正在使用一个包含有多个状态的 StateMachine 实例的类。状态本身可以通过初始化属性访问当前的 SKView。 States 负责呈现场景,因此它们有一个场景属性,将在 didEnter-Method 上呈现。 现在我有一个 MainMenuState,它有一个带有 3 个按钮的场景。为了将按钮事件传递给状态,我编写了一个自定义委托。 MainMenuState 实现委托协议并将场景的委托属性设置为“self”。因此,当用户点击按钮时,操作将转发到委托方法。我想使用委托方法转换到下一个状态(例如 SettingsState)。但是,当我尝试访问委托函数中的 GKStates StateMachine 属性时,它总是为零。 我认为我这里有一个设计问题,我不知道如何解决。

MainMenuState 的代码

import Foundation
import GameplayKit

class MainMenuState : GKState, MenuSceneDelegate {

    var view: SKView
    var scene: GKScene?

    init(view: SKView) {
        self.view = view;
        self.scene = GKScene(fileNamed: "MenuScene")
        super.init()
    }

    override func isValidNextState(_ stateClass: AnyClass) -> Bool {
        return stateClass is MultiplayerHostState.Type ||
        stateClass is MultiplayerSearchState.Type ||
        stateClass is SettingsState.Type
    }

    override func didEnter(from previousState: GKState?) {
        super.didEnter(from: previousState)
        // Load 'GameScene.sks' as a GKScene. This provides gameplay related content
        // including entities and graphs.
        if let scene = self.scene {

            // Get the SKScene from the loaded GKScene
            if let sceneNode = scene.rootNode as! MenuScene? {

                // Set delegate
                sceneNode.menuDelegate = self

                // Copy gameplay related content over to the scene
                sceneNode.entities = scene.entities
                sceneNode.graphs = scene.graphs

                // Set the scale mode to scale to fit the window
                sceneNode.scaleMode = .aspectFill
                sceneNode.size = view.bounds.size

                // Present the scene
                if let view = self.view as SKView? {
                    view.presentScene(sceneNode)

                    view.ignoresSiblingOrder = true

                    view.showsFPS = true
                    view.showsNodeCount = true
                }
            }
        }
    }



    override func willExit(to nextState: GKState) {
        super.willExit(to: nextState)
    }

    func hostGameClicked() {
        if let stateMachine = self.stateMachine {
            stateMachine.enter(MultiplayerHostState.self)
        }
    }

    func joinGameClicked() {
        if let stateMachine = self.stateMachine {
            stateMachine.enter(MultiplayerSearchState.self)
        }
    }

    func settingsClicked() {
// <-- Here the StateMachine is nil -->
        if let stateMachine = self.stateMachine {
            stateMachine.enter(SettingsState.self)
        }
    }
}

【问题讨论】:

    标签: swift sprite-kit gameplay-kit


    【解决方案1】:

    经过一番研究,我发现这种行为是由 Swifts ARC System 引起的。 持有状态机引用的类只在整个 ViewController 的函数中声明。所以在存在 func 之后,类和状态机被释放。 我在视图控制器中解决了它:

    class ViewController {
        var classWithStateMachine: ClassWithStateMachine?
    
        func initializeClassWithStateMachine {
            self.classWithStateMachine = ClassWithStateMachine()
        }
    }
    

    这段代码sn-p只是概念的演示,没有真正的代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-26
      相关资源
      最近更新 更多