Swift 3 (SpriteKit):游戏结束后重置 GameScene [英] Swift 3 (SpriteKit): Reseting the GameScene after the game ends

查看:23
本文介绍了Swift 3 (SpriteKit):游戏结束后重置 GameScene的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要重置"和重新启动"GameScene,就好像第一次调用了 GameScene.我已经查看了不同的方法来执行此操作,但是每次我收到警告说我正在尝试将节点添加到已经有父级的父级.但是,在我的代码中,我删除了所有现有节点,所以我对如何重置 GameScene 感到非常困惑.我现在就是这样做的(当我想从头开始重新启动 GameScene 时会调用此代码,并在 GameScene 类中调用它):

I am wanting to 'reset' and 'restart' the GameScene so it is as if the GameScene was first called. I have looked at different methods for doing this, but each time I get a warning that I'm trying to add a node to a parent which already has a parent. However, in my code I delete all my existing nodes so I'm really confused as to how to reset the GameScene. This is how I do it now (this code is called when I want to restart the GameScene from scratch and it is called within the GameScene class):

let scene = GameScene(size: self.size)
scene.scaleMode = .aspectFill
let animation = SKTransition.fade(withDuration: 1.0) 
self.view?.presentScene(scene, transition: animation)
self.removeAllChildren()
self.removeAllActions()
self.scene?.removeFromParent()

1.Edited: 我意识到为什么我会收到此警告:我正在尝试将节点添加到已经有父节点的父节点"是因为我在课堂之外拥有场景的所有变量并作为全局变量.但是,现在当游戏重新开始时,游戏在左下角.为什么会出现这种情况,我该如何解决?- 已修复

2.Edited: 现在一切正常,但现在我担心的是即使每个节点都没有调用 deinit{}被删除并且fps不会随着时间的推移而下降.这是我在 GameViewController 中用于设置场景和在 GameScene 中的内容(每个实例都与场景相关,所以基本上都是相关的):

2.Edited: Everything works fine now, but now my concern is that deinit{} isn't called even though every node is deleted and the fps doesn't drop over time. Here is what I have in my GameViewController for setting the scene and in my GameScene (every instance relating to the scenes so basically all that is relevant):

import UIKit
import SpriteKit
import GameplayKit

var screenSize = CGSize()

class GameViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    if let view = self.view as! SKView? {
        // Load the SKScene from 'GameScene.sks'
        if let scene = SKScene(fileNamed: "GameScene") {
            // Set the scale mode to scale to fit the window
            scene.scaleMode = .aspectFill
            screenSize = scene.size     
            // Present the scene
            view.presentScene(scene)
        }

        view.ignoresSiblingOrder = true

        view.showsFPS = true
        view.showsNodeCount = true
    }
}

那么我的GameScene基本上就是:

Then my GameScene is basically:

import SpriteKit
import GameplayKit

class GameScene: SKScene, SKPhysicsContactDelegate {
//Declare and initialise variables and enumerations here

deinit{print("GameScene deinited")}

override func didMove(to view: SKView) {
     //Setup scene and nodes
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    //Do other things depending on when and where you touch

    //When I want to reset the GameScene 
    let newScene = GameScene(size: self.size)
    newScene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    newScene.scaleMode = self.scaleMode
    let animation = SKTransition.fade(withDuration: 1.0)
    self.view?.presentScene(newScene, transition: animation)
}

任何答案将不胜感激:)

Any answers would be greatly appreciated :)

推荐答案

如何重置场景?

您只需随时再次呈现新的相同场景即可.所以,你做得很好.

You just have to present a new, same scene again whenever you want. So, you are doing it fine.

可能的泄漏问题?

另外,如果你的游戏没有泄漏,意味着没有强引用循环,你甚至不需要 self.removeAllChildren()self.removeAllActions()... 当然,如果您明确希望在过渡动画开始之前停止动作,那么使用这种方法是有意义的.关键是,当场景解除分配时,依赖于它的所有对象也应该/将解除分配.

Also, if you don't have leaks in your game, means no strong reference cycles, you don't even need self.removeAllChildren() and self.removeAllActions()... Of course if you explicitly want to stop actions before transition animation starts, the using this method make sense. The point is, when scene deallocates, all objects that depends on it should / will deallocate as well.

不过,如果您从一开始就不知道自己在做什么以及如何防止泄漏,例如.您在块中使用强自我,它是动作序列的一部分,它永远重复,那么您肯定有泄漏,并且 self.removeAllActions() 可能会有所帮助(在许多情况下,但它是不是最终解决方案).我建议阅读捕获列表和 ARC 一般来说,因为这些情况,了解所有这些是如何工作的会很有用.

Still, if you don't know from the beginning what you are doing and how to prevent from leaks, eg. you are using strong self in block which is a part of an action sequence, which repeats forever, then you certainly have a leak, and self.removeAllActions() might help (in many cases, but it is not an ultimate solution). I would recommend to read about capture lists and ARC in general because it can be useful to know how all that work just because of these situations.

场景是根节点

对场景本身调用 removeFromParent() 无效.场景是根节点,因此无法在当前上下文中删除.如果您检查场景的父属性,您会发现它是 nil.当然可以将一个场景添加到另一个场景,但在这种情况下,作为子节点添加的场景将充当普通节点.

Calling removeFromParent() on a scene itself has no effect. Scene is a root node, so it can't be removed in your current context. If you check scene's parent property you will notice that it is nil. Of course it is possible to add a scene to another scene, but in that case, the scene which is added as a child, will act as an ordinary node.

最后,如何呈现新场景?很简单,像这样:

And finally, how to present the new scene ? Easy, like this:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {


    let newScene = GameScene(size: self.size)
    newScene.scaleMode = self.scaleMode
    let animation = SKTransition.fade(withDuration: 1.0)
    self.view?.presentScene(newScene, transition: animation)


}

如果某些东西对您不起作用,则很可能存在泄漏(意味着您的场景未被释放).要检查这一点,请在 GameScene 中的某处覆盖 deinit 方法,如下所示:

If something doesn't work for you, it is likely that you have leaks (means your scene isn't deallocated). To check this, somewhere in your GameScene override deinit method, like this:

deinit{print("GameScene deinited")} 

为了进一步解释...应该发生的是,您应该呈现一个新场景,应该发生过渡,应该释放旧场景,并且应该看到具有初始状态的新场景.

To explain you this a bit further... What should happen is that you should present a new scene, a transition should occur, an old scene should be deallocated, and you should see a new scene with an initial state.

同样覆盖 deinit 只会告诉你场景是否被正确释放.但它不会告诉你为什么.您可以在代码中找到保留场景的内容.

Also overriding deinit will just tell you if the scene is deallocated properly or not. But it will not tell you why. It is up to you to find what in your code retaining the scene.

这篇关于Swift 3 (SpriteKit):游戏结束后重置 GameScene的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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