4

Swift で SpriteKit を使用してゲームを書いていますが、メモリの問題が発生しました。

私のゲームのレイアウトは、GameViewController (UIViewController) が最初の SKScene (levelChooserScene) を viewDidLoad 画面に表示するようなものです。このシーンは、たくさんのボタンを表示するだけです。ユーザーがボタンを選択すると、シーンは skView.presentScene を使用して正しいシーンに移行し、レベルが完了すると、そのシーンは levelChooserScene に戻り、ゲームはユーザーが次のレベルを選択できるようになります。

問題は、levelChooserScene に戻る遷移が発生したときに、ゲーム プレイ シーンに割り当てられたメモリの割り当てが解除されないことです。そのため、いくつかのレベルを選択しただけで、メモリ エラーが発生し始めます。

私の設計は SKScene から SKScene への遷移で正しいですか、それとも代わりに毎回 GameViewController に戻り、そこから次の SKScene に遷移する必要がありますか?

ここで、シーン間で skView.presentScene(nil) を呼び出す必要があるといういくつかの投稿を見つけましたが、それを実装する方法または場所について混乱しています。

ある SKScene から別の SKScene に移行し、送信シーンから使用されたメモリをシステムに戻したいだけです。

これは、SKScene の実装方法の例です。

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)
   }
}
4

2 に答える 2

1

問題の原因は、SKAction.repeatActionForever() を使用して 0.5 秒ごとにパーティクル エミッターを 5 秒間挿入し、エミッター挿入関数を呼び出すことでした。

この repeatAction は、別のシーンへの遷移によって強制終了されたのではなく、シーン全体のメモリが保持されていたようです。代わりに SKAction.repeatAction() に切り替えて、起動する回数を指定しました。新しいシーンに移行すると、シーンはすべてのメモリを返すようになりました。

ただし、この動作を理解しているかどうかはわかりません。

于 2015-04-19T20:30:27.427 に答える
1

複雑なゲームの作成に関しては、SpriteKit について詳しく文書化されていません。私はそれを理解することができるまで、個人的にこのような問題を何日も抱えていました。

一部のオブジェクトは参照を保持するため、deinit しません。(SKActions、タイマーなど)

新しいシーンを提示する前に、prepare_deinit()通常は迅速に割り当て解除されない強い参照を手動で削除する関数を呼び出します。

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()ため、新しいシーンを少し遅れて提示しなければならなかったことでした。

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)]))
于 2018-07-14T07:40:14.257 に答える