在我正在使用的SpriteKit游戏中:
self.scene!.removeFromParent()
let skView = self.view! as SKView
skView.ignoresSiblingOrder = true
var scene: PlayScene!
scene = PlayScene(size: skView.bounds.size)
scene.scaleMode = .AspectFill
skView.presentScene(scene, transition: SKTransition.fadeWithColor(SKColor(red: 25.0/255.0, green: 55.0/255.0, blue: 12.0/255.0, alpha: 1), duration: 1.0))
从一个场景移动到另一个场景。但是我怎样才能回到原来的场景呢?使用相同的代码原则总会导致严重的崩溃。
答案 0 :(得分:6)
我举了一个例子,其中全局结构用于跟踪previousScene
的信息。它也可以使用自定义属性,或者使用每个节点都有的userData。逻辑是一样的。此外,我已经删除了调试代码(调试标签代码等),因为它对所有工作都不重要。
如果我添加几个按钮,每个链接到特定场景,示例可能会更好,但我只留下一个按钮,以尽可能缩短所有内容。
您需要了解此示例(您将根据您的游戏更改此规则,但逻辑相同 - 在实际转换之前设置previousScene):
- 在你的GameViewController中,你应该将WelcomeScene设置为默认值。否则,您应该稍微更改一下代码以处理未设置previousScene时发生的情况(就像我在toussBegan的WelcomeScene中所做的那样)。
所以这些是我制定的规则,只是为了让所有这些过渡更有意义......
这是代码(BaseScene.swift):
import SpriteKit
enum SceneType: Int {
case WelcomeScene = 0
case MenuScene //1
case GameScene //2
}
struct GlobalData
{
static var previousScene:SceneType?
//Other global data...
}
class BaseScene:SKScene {
let button = SKSpriteNode(color: SKColor.blackColor(), size: CGSize(width: 50, height: 50))
override func didMoveToView(view: SKView) {
setupButton()
}
private func setupButton(){
if (button.parent == nil){
//Just setup button properties like position, zPosition and name
button.name = "goToGameScene"
button.zPosition = 1
button.position = CGPoint(x: CGRectGetMidX(frame), y: 100)
addChild(button)
}
}
func goToScene(newScene: SceneType){
var sceneToLoad:SKScene?
switch newScene {
case SceneType.GameScene:
sceneToLoad = GameScene(fileNamed: "GameScene")
case SceneType.MenuScene:
sceneToLoad = MenuScene(fileNamed: "MenuScene")
case SceneType.WelcomeScene:
sceneToLoad = WelcomeScene(fileNamed:"WelcomeScene")
}
if let scene = sceneToLoad {
scene.size = size
scene.scaleMode = scaleMode
let transition = SKTransition.fadeWithDuration(3)
self.view?.presentScene(scene, transition: transition)
}
}
}
每个场景(WelcomeScene,MenuScene,GameScene)都继承自BaseScene类(它是SKScene的子类)。我想,没有必要解释这个问题,但可以随意问一下是否有什么东西让你困惑。这里的重要方法(由每个子类使用)是goToScene(scene:SceneType)及其参数(类型为SceneType),它告诉我们方法应该加载什么类型的场景。
SceneType只是一个包含整数的枚举...所以实际上我们不在这里使用对象,因此不用担心strong reference cycles。
接下来,还有其他场景(WelcomeScene.swift):
import SpriteKit
class WelcomeScene:BaseScene {
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
self.backgroundColor = SKColor.darkGrayColor()
}
deinit {print ("WelcomeScene deinited")}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
if let location = touch?.locationInNode(self){
//Give a priority to a button - if button is tapped go to GameScene
let node = nodeAtPoint(location)
if node.name == "goToGameScene"{
GlobalData.previousScene = SceneType.MenuScene
goToScene(SceneType.GameScene)
}else{
//Otherwise, do a transition to the previous scene
//Get the previous scene
if let previousScene = GlobalData.previousScene {
GlobalData.previousScene = SceneType.WelcomeScene
goToScene(previousScene)
}else{
// There is no previousScene set yet? Go to MenuScene then...
GlobalData.previousScene = SceneType.WelcomeScene
goToScene(SceneType.MenuScene)
}
}
}
}
}
为了尽可能地保持简短,一切都被评论。下一个代码(MenuScene.swift):
import SpriteKit
class MenuScene: BaseScene {
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
backgroundColor = SKColor.purpleColor()
}
deinit {
print ("MenuScene deinited") //If this method isn't called, you might have problems with strong reference cycles.
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
if let location = touch?.locationInNode(self){
//Give a priority to a button - if button is tapped go to GameScene
let node = nodeAtPoint(location)
if node.name == "goToGameScene"{
GlobalData.previousScene = SceneType.MenuScene
goToScene(SceneType.GameScene)
}else{
//Otherwise, do a transition to the previous scene
//Get the previous scene
if let previousScene = GlobalData.previousScene {
GlobalData.previousScene = SceneType.MenuScene
goToScene(previousScene)
}
}
}
}
}
最后(GameScene.swift):
import SpriteKit
class GameScene: BaseScene{
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
self.backgroundColor = SKColor.orangeColor()
}
deinit {print ("GameScene deinited")}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//Here, we ignore black button because we don't want to transition to the same scene
if let previousScene = GlobalData.previousScene {
GlobalData.previousScene = SceneType.GameScene
goToScene(previousScene)
}
}
}
预览:
从头开始再次阅读规则,你就可以了(例如,在GameScene黑色按钮不起作用,或者在第一次启动时没有设置previousScene,所以默认情况下你将转换到MenuScene)。 / p>
那就是它。希望这个对你有帮助。您可以复制并粘贴代码以对其进行测试,并根据您的需要进行改进。不过,还不确定你真的需要这个。看起来您只需要correctly transition between scenes。
提示:这里重要的是每个场景BaseScene,WelcomeScene ...都有自己的.sks文件。您可以从File-&gt; New-&gt; File-&gt; Resource创建它们并对其进行适当命名(如BaseClass.sks,WelcomeScene.sks ...)此外,保持GlobalData.previousScene
的状态是您的工作。变量(例如,在转换之前设置它)。
答案 1 :(得分:1)
您需要在新场景中创建一个存储前一个属性的属性,例如previousScene
。然后你可以这样设置:scene.previousScene = self.scene
。在新场景中,您现在可以使用skView.presentScene(previousScene)
我建议不要命名你要呈现的新场景scene
,因为你当前的场景也被称为场景,所以如果你不小心忘记了self
中的self.scene
那么这可能会引起很多混乱。我将其命名为newScene
或sceneToPresent
。
此外,您的第一行self.scene!.removeFromParent()
不是必需的。在呈现新场景之前,您无需删除当前场景。