所以我正在开发一个包含SpriteKit游戏的应用程序。我注意到的是,在我开始和关闭游戏后,内存不断增加,如下图所示:
我使用模态演示文稿从View Controller呈现游戏。所以问题是: 有没有办法从内存中完全删除场景?
我正在点击View Controller上的关闭按钮以关闭它。 scene.quitGame()
方法基本上解除了所有节点,动作等的释放。在一个理想的世界中,我甚至不需要做任何这样的事情,因为会有一个完全摆脱SKScene
的魔法命令。
@IBAction func quit(_ sender: UIButton) {
scene.quitGame()
scene.removeFromParent()
self.removeFromParentViewController()
self.dismiss(animated: true, completion: nil)
scene = nil
}
编辑:我使用以下代码从viewDidLoad呈现场景:
scene = GameScene(size: view.bounds.size)
let skView = view as! SKView
skView.showsFPS = false
skView.showsNodeCount = false
skView.ignoresSiblingOrder = true
scene.scaleMode = .resizeFill
if let heroImage2 = heroImage2, let myImage = myImage, let monsterImage = monsterImage{
scene.addPicture(img: heroImage2, myImage: myImage,monsterImage: monsterImage, bigMonsterImage: bigMonsterImage!)
}
skView.presentScene(scene)
scene.viewController = self
编辑2 - 我注释了对此方法的调用,其中包括重复永久动作,泄漏似乎消失了
func createHerosAction(duration: Double = 5.0){
run(SKAction.repeatForever(
SKAction.sequence([
SKAction.run(addHero),
SKAction.wait(forDuration: duration)
])
), withKey:"createHeros")
}
func addHero() {
// Create sprite
if(heroImage == nil){
heroImage = UIImage(named: "hero")
}
let Texture = SKTexture(image: heroImage!)
let hero = SKSpriteNode(texture:Texture)
hero.size.width = size.width * 0.17
hero.size.height = hero.size.width
hero.name = "hero"
hero.zPosition = 2
let heroSide = arc4random_uniform(2)
hero.physicsBody = SKPhysicsBody(rectangleOf: hero.size) // 1
hero.physicsBody?.isDynamic = true // 2
hero.physicsBody?.categoryBitMask = PhysicsCategory.Hero // 3
hero.physicsBody?.contactTestBitMask = PhysicsCategory.Projectile // 4
hero.physicsBody?.collisionBitMask = PhysicsCategory.None // 5
let actualY = random(min: size.height*0.3 + hero.size.height/2 + size.height * 0.12, max: size.height - hero.size.height/2 - size.height * 0.15)
let pointRightOfScreen = CGPoint(x: size.width + hero.size.width/2, y: actualY)
let pointLeftOfScreen = CGPoint(x: -hero.size.width/2, y: actualY)
if(heroSide == 0){
hero.position = pointRightOfScreen
}else{
hero.position = pointLeftOfScreen
}
addChild(hero)
let actualDuration = random(min: CGFloat(2.0), max: CGFloat(5.0))
var actionMove = SKAction()
if(heroSide == 0){
actionMove = SKAction.move(to: pointLeftOfScreen, duration: TimeInterval(actualDuration))
}else{
actionMove = SKAction.move(to: pointRightOfScreen, duration: TimeInterval(actualDuration))
}
let numberOfUpsAndDown = random(min: CGFloat(1.0), max: CGFloat(10.0))
let variance = random(min: CGFloat(-70.0), max: CGFloat(70.0))
let mvHero = moveHeroUpAndDown(node: hero, variance: variance,duration: actualDuration/numberOfUpsAndDown)
let actionMoveDone = SKAction.removeFromParent()
let loseLifeAction = loseLife(node: hero)
hero.run(SKAction.sequence([actionMove, loseLifeAction, actionMoveDone]), withKey: "moveHero")
hero.run(mvHero, withKey: "UpAndDown")
}
编辑3:泄漏似乎是在上面调用的SKAction上。在我删除此操作后,泄漏停止了。
func loseLife(node: SKSpriteNode) -> SKAction{
let loseALifeAction = SKAction.run(){
if(self.gamePaused == false){
self.playSound(fileName: "losesound.wav")
if(self.lives > 0){
self.updateLives(newValue: self.lives - 1, lostLife: true)
//self.lives -= 1
}
print("lives: \(self.lives)")
if(self.lives <= 0){
print("hit me")
node.run(self.loseGame())
}
}
}
return loseALifeAction
}
答案 0 :(得分:5)
根据您的评论,您应该使用capture lists:
func createHerosAction(duration: Double = 5.0){
run(SKAction.repeatForever(
SKAction.sequence([
SKAction.run {[unowned self] in
self.addHero()
},
SKAction.wait(forDuration: duration)
])
), withKey:"createHeros")
}
这是一个很大的话题,但我建议你开始阅读我发布的链接,因为它已经详细解释了从&#34; ARC如何工作&#34;,&#34;什么是捕获列表& #34;对弱者和无主义的关键词。我已经写了好几次关于这个,以及这个网站上的许多其他人,这是一个很大的话题,所以这次我会跳过:)
答案 1 :(得分:0)
我相信它的内部SpriteKit泄漏将ViewController保存在内存中。我们发现SpriteKit在解除了viewController之后似乎保留了Scene和SKView。
在我们的案例中,我们开始专门在比赛结束后呈现一个零场景,就在我们通过屏幕呈现游戏之后。
// Remove the game scene to stop game code and free up memory
if let skView = view as? SKView {
skView.presentScene(nil)
}