Sprite Kit:仅为所有场景创建一次节点

suy*_*ama 5 singleton sprite-kit

通常在精灵套件游戏中,当呈现新场景时,旧场景中的所有节点及其内容自动被移除.那么,如果不删除像"HUD"这样的节点呢?精灵套件中是否有任何方法只创建一个节点并在所有场景中使用它而不必每次在每个新场景中一次又一次地删除和创建它?必须有一种技术使其成为可能.这是一个严重的精灵套件设计问题,如果不可能的话.但我不这么认为.单例技术适用于音频播放器,它只创建一次并用于所有场景.有一种方法只能创建一个节点并在所有场景中使用它.谢谢你的想法.

Epi*_*yte 11

您无法创建在场景之间保留的节点.呈现新场景后,您需要将节点添加到此新场景中.

因此,由于此问题,我不像Apple在文档中描述的那样使用SKScenes.每次必须将节点添加到新场景中不仅麻烦,而且对于应始终存在的后台节点等节点而言效率极低.

所以我做的是创建2个场景,一个用于游戏场景,一个用于菜单(GUI).

对于菜单场景,我为我的界面子类化了SKNodes,然后在这些节点上使用SKActions在屏幕上显示和消除它们,这样就感觉用户正在场景之间转换.这为您提供了全面的自定义,因为您可以呈现多个节点,您可以永久保留屏幕上的节点等.

通过子类化SKNodes,您可以像处理场景一样组织代码.每个节点都代表您应用中的"场景".然后你只需要编写一个方法来呈现和解除这些节点.


我已经添加了下面的一些示例代码显示一个实现利用SKNodes作为"场景".示例代码有一个基类SceneNode,我们将其子类化(就像您将子类化一样SKScene).在这个实现中,我使用它GameScene来处理场景节点之间的所有转换*.我还跟踪当前场景节点,以便我可以在场景改变大小时更新其布局(例如在OS X**上旋转或窗口调整大小).您的游戏可能不需要这个,但它是动态布局节点的好方法.任何你想要添加到背景或保留的东西,只需将其添加到GameScene.你想要添加到场景中的任何东西,只需子类化SceneNode,过渡到它,你的好处就可以了.

*您可以直接从其他场景节点轻松呈现场景节点,而不是通过GameScene.但是我发现使用GameScene来处理节点之间的转换非常有效,特别是当你有很多具有复杂转换的场景时.
**OS X上有一个错误,调整窗口大小不会调用场景的didChangeSize.你需要手动调用它.

class GameViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let scene = GameScene(size:self.view.bounds.size)
        scene.scaleMode = .ResizeFill
        (self.view as! SKView).presentScene(scene)
    }
}

class GameScene: SKScene {
    var currentSceneNode: SceneNode!

    override func didMoveToView(view: SKView) {
        self.backgroundColor = SKColor.whiteColor()
        transitionToScene(.Menu)
    }
    override func didChangeSize(oldSize: CGSize) {
        currentSceneNode?.layout()
    }
    func transitionToScene(sceneType: SceneTransition) {
        switch sceneType {
        case .Menu:
            currentSceneNode?.dismissWithAnimation(.Right)
            currentSceneNode = MenuSceneNode(gameScene: self)
            currentSceneNode.presentWithAnimation(.Right)

        case .Scores:
            currentSceneNode?.dismissWithAnimation(.Left)
            currentSceneNode = ScoresSceneNode(gameScene: self)
            currentSceneNode.presentWithAnimation(.Left)

        default: fatalError("Unknown scene transition.")
        }
    }
}

class SceneNode: SKNode {
    weak var gameScene: GameScene!

    init(gameScene: GameScene) {
        self.gameScene = gameScene
        super.init()
    }
    func layout() {}
    func presentWithAnimation(animation:Animation) {
        layout()
        let invert: CGFloat = animation == .Left ? 1 : -1
        self.position = CGPoint(x: invert*gameScene.size.width, y: 0)
        gameScene.addChild(self)
        let action = SKAction.moveTo(CGPoint(x: 0, y: 0), duration: 0.3)
        action.timingMode = SKActionTimingMode.EaseInEaseOut
        self.runAction(action)
    }
    func dismissWithAnimation(animation:Animation) {
        let invert: CGFloat = animation == .Left ? 1 : -1
        self.position = CGPoint(x: 0, y: 0)
        let action = SKAction.moveTo(CGPoint(x: invert*(-gameScene.size.width), y: 0), duration: 0.3)
        action.timingMode = SKActionTimingMode.EaseInEaseOut
        self.runAction(action, completion: {self.removeFromParent()})
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


class MenuSceneNode: SceneNode {
    var label: SKLabelNode
    var container: SKSpriteNode

    override func layout() {
        container.position = CGPoint(x: gameScene.size.width/2.0, y: gameScene.size.height/2.0)
    }
    override init(gameScene: GameScene) {
        label = SKLabelNode(text: "Menu Scene")
        label.horizontalAlignmentMode = .Center
        label.verticalAlignmentMode = .Center
        container = SKSpriteNode(color: UIColor.blackColor(), size: CGSize(width: 200, height: 200))
        container.addChild(label)
        super.init(gameScene: gameScene)
        self.addChild(container)
        self.userInteractionEnabled = true
    }
    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        self.gameScene.transitionToScene(.Scores)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class ScoresSceneNode: SceneNode {
    var label: SKLabelNode
    var container: SKSpriteNode

    override func layout() {
        container.position = CGPoint(x: gameScene.size.width/2.0, y: gameScene.size.height/2.0)
    }
    override init(gameScene: GameScene) {
        label = SKLabelNode(text: "Scores Scene")
        label.horizontalAlignmentMode = .Center
        label.verticalAlignmentMode = .Center
        container = SKSpriteNode(color: UIColor.blackColor(), size: CGSize(width: 200, height: 200))
        container.addChild(label)
        super.init(gameScene: gameScene)
        self.addChild(container)
        self.userInteractionEnabled = true
    }
    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        self.gameScene.transitionToScene(.Menu)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

enum SceneTransition{
    case Menu, Scores
}
enum Animation {
    case Left, Right, None
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述