#swift #sprite-kit #gameplay-kit
#swift #sprite-kit #игровой процесс-комплект
Вопрос:
Я разрабатываю игру 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:
После некоторых исследований я выяснил, что такое поведение было вызвано системой Swifts ARC. Класс, содержащий ссылку на конечный автомат, был объявлен только в функции общего ViewController. Итак, после создания функции класс и конечный автомат были освобождены. Я решил это в контроллере просмотра:
class ViewController {
var classWithStateMachine: ClassWithStateMachine?
func initializeClassWithStateMachine {
self.classWithStateMachine = ClassWithStateMachine()
}
}
Этот фрагмент кода — просто демонстрация концепции, никакого реального кода.