GKState: почему StateMachine == ноль при вызове делегата? - PullRequest
0 голосов
/ 21 апреля 2019

Я разрабатываю игру SpriteKit, используя GKStateMachine для перехода между несколькими сценами.Я использую класс, который содержит экземпляр StateMachine, который имеет несколько состояний.Сами состояния имеют доступ к текущему SKView через свойство инициализатора.Штаты отвечают за представление сцен, поэтому у них есть свойство сцены, которое будет представлено в методе didEnter.Теперь у меня есть 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)
        }
    }
}

1 Ответ

0 голосов
/ 25 апреля 2019

После некоторых исследований я обнаружил, что такое поведение было вызвано системой Swifts ARC. Класс, содержащий ссылку на конечный автомат, был объявлен только в рамках функции общего ViewController. Таким образом, после существования функции класс и конечный автомат были освобождены. Я решил это в View Controller:

class ViewController {
    var classWithStateMachine: ClassWithStateMachine?

    func initializeClassWithStateMachine {
        self.classWithStateMachine = ClassWithStateMachine()
    }
}

Этот фрагмент кода является просто демонстрацией концепции, а не реального кода.

...