Как я уже говорил, ваш вопрос немного расплывчатый, но позволяет сделать несколько примеров того, что может быть классом GameManager.
Перед тем, как начать позволяет различать вызова этого
let scene = StartScene(size: ...)
и этот
let scene = SKScene(fileNamed: "StartScene")
1-ый метод, с размером, когда вы создаете свои сцены все в коде, и вы не используете xCode визуальный редактор уровня.
Второй метод - это когда вы используете редактор уровня Xcode, поэтому вам нужно будет создать файл StartScene.sks. Его файл .sks, который он ищет в fileNamed.
Теперь, для примера некоторых игровых менеджеров, сначала представим себе, что у нас есть 3 SKScenes.
class StartScene: SKScene {
override func didMove(to view: SKView) { ... }
}
class GameScene: SKScene {
override func didMove(to view: SKView) { ... }
}
class GameOverScene: SKScene {
override func didMove(to view: SKView) { ... }
}
Допустим, вы хотите, чтобы перейти от StartScene к GameScene, вы бы добавить этот код в StartScene на правильном месте, когда например нажата кнопка воспроизведения. Это самый простой способ перехода от одного SKScene к другому, непосредственно из самого SKScene.
// Code only, no xCode level editor
let gameScene = GameScene(size: CGSize(...))
let transition = SKTransition...
gameScene.scaleMode = .aspectFill
view?.presentScene(gameScene, transition: transition)
// With xCode level editor (returns an optional so needs if let
// This will need the GameScene.sks file with the correct custom class set up in the inspector
// Returns optional
if let gameScene = SKScene(fileNamed: "GameScene") {
let transition = SKTransition...
gameScene.scaleMode = .aspectFill
view?.presentScene(gameScene, transition: transition)
}
Теперь для некоторых реальных примеров GameManager, я уверен, что вы знаете о некоторых из них уже.
Пример 1
Допустим, мы хотим, чтобы менеджер загрузки сцены. Подход со статическими методами не будет работать, потому что новый экземпляр SKScene необходимо создать при переходе на один, иначе такие вещи, как враги и т. Д., Не будут сброшены. Ваш подход со статическими методами означает, что вы будете использовать один и тот же экземпляр каждый раз, и это не хорошо.
Я лично использую расширение протокола для этого. Создать новый файл .swift и назовите его SceneLoaderManager или что-то и добавить этот код
enum SceneIdentifier: String {
case start = "StartScene"
case game = "GameScene"
case gameOver = "GameOverScene"
}
private let sceneSize = CGSize(width: ..., height: ...)
protocol SceneManager { }
extension SceneManager where Self: SKScene {
// No xCode level editor
func loadScene(withIdentifier identifier: SceneIdentifier) {
let scene: SKScene
switch identifier {
case .start:
scene = StartScene(size: sceneSize)
case .game:
scene = GameScene(size: sceneSize)
case .gameOver:
scene = GameOverScene(size: sceneSize)
}
let transition = SKTransition...\
scene.scaleMode = .aspectFill
view?.presentScene(scene, transition: transition)
}
// With xCode level editor
func loadScene(withIdentifier identifier: SceneIdentifier) {
guard let scene = SKScene(fileNamed: identifier.rawValue) else { return }
scene.scaleMode = .aspectFill
let transition = SKTransition...
view?.presentScene(scene, transition: transition)
}
}
В настоящее время в 3-х сценах соответствовать протоколу
class StartScene: SKScene, SceneManager { ... }
и вызвать метод нагрузки, как это так, используя 1 из 3 перечислений в качестве идентификатора сцены.
loadScene(withIdentifier: .game)
Пример 2
Позволяет сделать класс менеджера игра для игровых данных, используя подход Singleton.
class GameData {
static let shared = GameData()
private init() { } // Private singleton init
var highscore = 0
func updateHighscore(forScore score: Int) {
guard score > highscore else { return }
highscore = score
save()
}
func save() {
// Some code to save the highscore property e.g UserDefaults or by archiving the whole GameData class
}
}
Теперь в любом месте вашего проекта вы можете сказать
GameData.shared.updateHighscore(forScore: SOMESCORE)
Вы склонны использовать Singleton для вещей, где вам нужно только 1 экземпляр класса. Хороший пример использования классов Singleton бы такие вещи, как вспомогательные классы для Game Center, InAppPurchases, GameData и т.д.
Примера 3
Помощников для хранения некоторых значений, которые могут понадобиться во всех сценах. Это использует метод статического метода, аналогичный тому, что вы пытались сделать. Мне нравится использовать это для таких вещей, как настройки игры, чтобы они были в хорошем централизованном месте.
class GameHelper {
static let enemySpawnTime: TimeInterval = 5
static let enemyBossHealth = 5
static let playerSpeed = ...
}
Используйте их, как это в ваших сценах
... = GameHelper.playerSpeed
Пример 4
класс для управления SKSpriteNodes например врагов
class Enemy: SKSpriteNode {
var health = 5
init(imageNamed: String) {
let texture = SKTexture(imageNamed: imageNamed)
super.init(texture: texture, color: SKColor.clear, size: texture.size())
}
func reduceHealth(by amount: Int) {
health -= amount
}
}
чем в вашей сцене, вы можете создать врагов, использующих этот вспомогательный класс и вызывающих методы и p на нем. Таким образом, вы можете добавить 10 врагов легко и индивидуально управлять своим здоровьем и т.д. например
let enemy1 = Enemy(imageNamed: "Enemy1")
let enemy2 = Enemy(imageNamed: "Enemy2")
enemy1.reduceHealth(by: 3)
enemy2.reduceHealth(by: 1)
Его массивный ответ, но я надеюсь, что это помогает.
Ваш метод init вызывает себя рекурсивно, что вызывает переполнение * стека * :) –
Сравнить http://stackoverflow.com/questions/30798642/overriding-init-in-a-customuiview-crashes-app-exc-bad -access, который, похоже, касается одной и той же проблемы в подклассе UIView. –
Хотелось бы, чтобы это было легко, для меня, чтобы понять. Если я изменю self.init() на super.init(), я получаю ошибку: «Инициализатор удобства для« SecondScene »должен делегировать с self.init, а не привязывать к суперклассу ... – Confused