Sprite Kit:为所有场景只创建一次节点 [英] Sprite Kit: create node only once for all scenes

查看:21
本文介绍了Sprite Kit:为所有场景只创建一次节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Normally in a sprite kit game, when a new scene presented, all the nodes in the old scene and their content removed automatically. Now what is, if a node like "HUD" should be not removed? Is there any way in sprite kit to create a node only once and use it in all scenes without removing and creating it again and again every time in every new scene? There must be a technique that makes it possible. that's a serious sprite kit design problem, if it is not possible. But I don't think so. The singleton technique is working great with an audio player, that created only once and used in all scenes. There is surley a way to create a node only once and use it in all scenes. Thanks for any idea.

推荐答案

您无法创建在场景之间持续存在的节点.呈现新场景后,您需要将节点添加到这个新场景.

You can't create a node that persists between scenes. Once you present a new scene, you would need to add the nodes to this new scene.

出于这个原因,由于这个问题,我没有按照 Apple 在文档中描述的方式使用 SKScenes.不仅每次都必须将节点添加到新场景中很麻烦,而且对于像后台节点这样应该始终存在的节点来说效率也非常低.

For this reason, I do not use SKScenes the way Apple describes in the documentation because of this issue. Not only is it cumbersome to have to add the nodes to the new scene each time but also extremely inefficient for nodes like background nodes that should always be present.

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

So what I did is create 2 scenes, one for the game scene and one for the menu (GUI).

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

For the menu scene I subclass SKNodes for my interface and then use SKActions on these nodes to present and dismiss them on the screen so it feels like the user is transitioning between scenes. This gives you total customization because you can present multiple nodes, you can keep nodes on the screen permanently etc.

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

By subclassing the SKNodes you can organize your code just as you did for the scenes. Each node will represent a "scene" in your App. Then you just need to write a method to present and dismiss these nodes.

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

I've added some sample code below to show one implementation of using SKNodes as "Scenes." The sample code has a base class called SceneNode which we subclass (just as you would subclass an SKScene). In this implementation, I use the GameScene to handle all transitions between scene nodes*. I also keep track of the current scene node so that I can update its layout in case the scene changes size (such as rotation or window resize on OS X**). Your game might not need this, but it's a great way to dynamically layout your nodes. Anything that you want to add to the background or keep around, simply add it to the GameScene. Anything that you want to add to a scene, simply subclass a SceneNode, transition to it and your good to go.

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

*You could easily present scene nodes directly from other scene nodes instead of going through the GameScene. However I have found that using the GameScene to handle transitions between nodes works very well, especially when you have many scenes with complex transitions.
**There is a bug on OS X, resizing the window does not call the scene's didChangeSize. You need to manually call it.

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
}

<小时>

这篇关于Sprite Kit:为所有场景只创建一次节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆