0

I have 3 SKScenes in SpriteKit, Swift:

  • Level 1

  • Game Over

  • Level 2.

In Level 1 and Level 2, my character movement is done by the following code:

class Level1: SKScene, SKPhysicsContactDelegate {

func swipedRight(sender:UISwipeGestureRecognizer){
    let moveRIGHT = SKAction.moveBy(CGVectorMake(60, 0), duration: 1)
    Character.runAction(moveRIGHT)
    }

func swipedLeft(sender:UISwipeGestureRecognizer){
    let moveLEFT = SKAction.moveBy(CGVectorMake(-60, 0), duration: 1)
    Character.runAction(moveLEFT)
    }


let swipeRight:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("swipedRight:"))
swipeRight.direction = .Right
view.addGestureRecognizer(swipeRight)

let swipeLeft:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("swipedLeft:"))
swipeLeft.direction = .Left
view.addGestureRecognizer(swipeLeft)

And when the character dies in Level 1, I transition to the "Game Over" SKScene where you can retry Level 1 if you'd like.

However after going back and forth between Level 1 - Game Over - Level 1 - Game Over - Level 1 - Game Over etc, the FPS dramatically drops whenever you do a UISwipeGesture on Level 1 AND Level 2.

I then decided to remove the UISwipeGestureRecognizer from Level 1, and then purposely go back and forth between Level 1 and Game Over, and then go to Level 2. There was no FPS drop when using UISwipeGestures in Level 2 after doing this.

Therefore, my conclusion is that whenever I load a SKScene with the UISwipeGestureRecognizer over and over again, it creates this FPS drop whenever you try and initiate a swipe.

So: 1) Am I implementing this UISwipeGestureRecognizer wrongly?

2) Is there another way I can get the same effect of character movement without using UISwipeGestureRecognizer?

Thanks heaps guys!

  • Like crashoverride777 pointed, every time a scene is loaded, you are adding new gesture recognizers over and over again. You can check this with : print(view.gestureRecognizers?.count). Here is additional example of how you can remove your recognizers : http://stackoverflow.com/a/27884853/3402095 – Whirlwind Dec 12 '15 at 13:41
  • Thanks for the reference and how to check the gesture recogniser count. I just went though all my SKScene's and used the print function. All came back Nil after transitioning scenes. Like you said, I was adding a new gesture recogniser over and over. Cheers! –  Dec 12 '15 at 16:25

1 Answers1

2

You need to remove the gestures before transitioning to a new scene, otherwise the same gestures keep getting added over and over again which causes the FPS issues. If you for example would have different gestures in level 2 scene than level 1 scene your game will crash because the old level1 gestures have not been removed. Try this before changing scenes

guard let view = view else { return }
guard view.gestureRecognizers != nil else { return }
for gesture in view.gestureRecognizers! {
    if let recognizerTap = gesture as? UITapGestureRecognizer {
       view.removeGestureRecognizer(recognizerTap)
    }
    if let recognizerSwipe = gesture as? UISwipeGestureRecognizer {
       view.removeGestureRecognizer(recognizerSwipe)
    }
 }

Also to make your live easier you should probably start subclassing. Consider making a BaseScene class which houses all the properties, controls, player sprite, labels etc that you show in all level scenes. Otherwise if you for example have 20 levels you need to copy way too much code. Its super simple

Make a BaseScene like so

 class BaseScene: SKScene, SKPhysicsContactDelegate {

and just set up the gestures and all the stuff you need for all your levels in the ViewDidLoad method. Also use baseScene for your contact methods and other stuff you need shared between levels (gameOver method etc)

Than in your level scenes you should subclass them like so

  class Level1Scene: BaseScene {

  override func didMoveToView(view: SKView) {
  super.didMoveToView(view) // imports everything from ViewDidLoad in base scene

  // do other setUps specific to level 1 only

This wil make you code way more flexible. Say you use the Update func in BaseScene to pause the game, it will work in subclass level scenes as described above. But for example if in Level2 you need to add a method to the Update func that only runs in Level2 you can do something similar to the ViewDidLoad method. So in your Level 2 scene you could say this

 override func update(currentTime: CFTimeInterval) {
     super.update(currentTime) // will use all BaseScene update methods

    // do something specific for level 2 only

Now if you want something in update that only runs in Level2 scene and ignores all the update Methods in BaseScene than you simply dont call

 super.update(currentTime)

This applies to almost all methods, like the contact methods, touches began etc. Its the way to go.

crashoverride777
  • 10,581
  • 2
  • 32
  • 56
  • crashoverride777, I just tested the code you gave me. Not a single frame drop after transition scenes 100 times. Thank you so much! I had been trying to fix this problem in my code for ages. I knew there was something wrong with my UISwipeGestureRecognizer but didn't know how to fix it. Also, thanks for going the extra mile in explaining "BaseScene". I do in fact copy a lot of code for all my levels haha You read my mind. Cheers! –  Dec 12 '15 at 16:24
  • You are very welcome. Common mistake that people make in the beginning, including myself. – crashoverride777 Dec 12 '15 at 16:40