首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SpriteKit场景转换良好实践

SpriteKit场景转换良好实践
EN

Stack Overflow用户
提问于 2015-04-19 19:24:26
回答 2查看 1.6K关注 0票数 4

我正在用Swift编写一个使用SpriteKit的游戏,并且遇到了内存问题。

我的游戏布局是这样的,GameViewController (UIViewController)在viewDidLoad屏幕上显示了第一个SKScene (levelChooserScene)。这一幕只会显示一堆按钮。当用户选择一个按钮时,场景然后使用skView.presentScene切换到正确的场景,当级别完成时,该场景将切换回levelChooserScene,游戏为用户选择下一个级别做好了准备。

问题是,当转换回levelChooserScene时,分配给游戏场景的内存并没有被释放,所以在选择了几个级别之后,我开始接收内存错误。

我的设计在从SKScene过渡到SKScene时是正确的,还是应该每次返回到GameViewController,然后从那里转换到下一个SKScene?

我在这里找到了一些帖子,上面说我应该在场景之间调用skView.presentScene(0),但我对如何或在何处实现这一点感到困惑。

我只是想从一个SKScene转换到另一个,并将从输出场景中使用的内存返回到系统。

这是我如何实现SKScene的一个例子:

代码语言:javascript
运行
复制
class Level3: SKScene
{
   var explodingRockTimer = NSTimer()
   var blowingUpTheRocks = SKAction()

   override func didMoveToView(view: SKView)
   {
       NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "dismissTheScene:", userInfo: nil, repeats: false)
       var wait = SKAction.waitForDuration(0.5)
       var run = SKAction.runBlock{
           // your code here ...
           self.explodeSomeRocks()
       }
       let runIt = SKAction.sequence([wait,run])
       self.runAction(SKAction.repeatActionForever(runIt), withKey: "blowingUpRocks")

       var dismissalWait = SKAction.waitForDuration(5.0)
       var dismissalRun = SKAction.runBlock{
           self.removeActionForKey("blowingUpRocks")
           self.dismissTheScene()

       }
       self.runAction(SKAction.sequence([dismissalWait,dismissalRun]))
   }

   func explodeSomeRocks()
   {
       println("Timer fired")
   }

   //MARK: - Dismiss back to the level selector
   func dismissTheScene()
   {
       let skView = self.view as SKView?
       var nextScene = SKScene()

       nextScene = LevelChooserScene()
       nextScene.size = skView!.bounds.size
       nextScene.scaleMode = .AspectFill
       var sceneTransition = SKTransition.fadeWithColor(UIColor.blackColor(), duration: 1.5) //WithDuration(2.0)
       //var sceneTransition = SKTransition.pushWithDirection(SKTransitionDirection.Down, duration: 0.75) //WithDuration(2.0)
       //var sceneTransition = SKTransition.crossFadeWithDuration(1.0)
       //var sceneTransition = SKTransition.doorwayWithDuration(1.0)
       sceneTransition.pausesOutgoingScene = true

       skView!.presentScene(nextScene, transition: sceneTransition)
   }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-04-19 20:30:27

造成我麻烦的地方是每半秒钟插入粒子发射器5秒,使用SKAction.repeatActionForever()调用发射器插入函数。

这个repeatAction显然不是通过转换到另一个场景而被杀死的,并且导致整个场景的记忆被保留。我转而使用了SKAction.repeatAction(),并指定了它应该触发的时间。当我转换到新场景时,这个场景现在返回了它的所有记忆。

不过,我不确定我是否理解这种行为。

票数 1
EN

Stack Overflow用户

发布于 2018-07-14 07:40:14

SpriteKit --当涉及到创建复杂的游戏时,并没有很强的文档记录。几天来,我一直有这样的问题,直到我想出了办法。

有些对象保留引用,因此它不会删除引用。(SKActions、计时器等)

在展示一个新场景之前,我调用一个prepare_deinit()函数,在这里我手动删除强引用,这些引用通常不会被swift释放。

代码语言:javascript
运行
复制
func prepare_deinit()
{
    game_timer.invalidate() // for Timer()
    removeAction(forKey: "blowingUpRocks") // for SKAction in your case

    // I usually add the specific actions to an object and then remove 
    object.removeAllActions()

    // If you create your own object/class that doesn't deinit, remove all object 
    //actions and the object itself
    custom_object.removeAllActions()
    custom_object.removeFromParent()

}

deinit
{
   print("GameScene deinited")
}

我遇到的最后一个问题是,新场景的呈现速度比我的prepare_deinit()快得多,所以我不得不在稍晚一些时候呈现新场景,给prepare_deinit()足够的时间来释放所有对象。

代码语言:javascript
运行
复制
let new_scene =
{
   let transition = SKTransition.flipVertical(withDuration: 1.0)
   let next_scene = FinishScene(fileNamed: "FinishScene")
   next_scene?.scaleMode = self.scaleMode
   next_scene?.name = "finish"
   self.view?.presentScene(next_scene!, transition: transition)
}

run(SKAction.sequence([SKAction.run(prepare_deinit), SKAction.wait(forDuration: 0.25), SKAction.run(exit_to_finish)]))
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29734729

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档