2

I am making an iOS game using Swift. At the menu (Menu is a SKScene), I have a button that starts the game, let's call it 'start button'. When I hit the start button, application freezes and loads the gameplay (gameplay is a SKScene), then transition animation runs and gameplay begins. But instead of the freeze of the application, I want a rotating loading circle while application loads the gameplay. How can I do that? Ask me if there is something not clear...

func loadingScreen(scene:SKScene) {
    var loadingSprite = SKSpriteNode(imageNamed: "loading.png")
    loadingSprite.size = CGSize(width: 100, height: 100)
    loadingSprite.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
    loadingSprite.zPosition = 10
    self.addChild(loadingSprite)
    loadingSprite.runAction(SKAction.repeatActionForever(SKAction.rotateByAngle(3, duration: 0.5)))
    let qualityOfServiceClass = QOS_CLASS_BACKGROUND
    let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
    dispatch_async(backgroundQueue, {
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.view!.presentScene(scene, transition: SKTransition.fadeWithDuration(1.0))
        })

    })
}

And it is the secondScene's initializer;

convenience init (size:CGSize,mode:String) {
    self.init(size:size)
    self.gameMode = mode
    loadItems() //loads my custom objects 
    printSlider() // printing sprites depending to my objects
}
white5tone
  • 166
  • 8

2 Answers2

1

Here is how I handle loading a scene in my game. I add a node to the menu scene and apply an action to it to keep it animating. I then initialize my scene on the background thread so that the main thread doesn't get blocked (remember the main thread handles visual rendering). Finally, after the scene finishes loading, I present the scene back on the main thread. Here is the code for it below.

let loadingSprite = YourLoadingSprite()
self.sceneView.scene!.addChild(loadingSprite)

let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
    self.gameScene = GameScene()
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        self.sceneView.presentScene(self.gameScene, transition: SKTransition.fadeWithDuration(1.0))
     })

})

Update
In your code you are not initializing the scene on the background thread. Your scene is already initialized when this method is called. You need to initialize your scene in this method but dispatch it onto the background thread. In the code below I put a comment showing your where you should initialize your scene.

func loadingScreen() {
    var loadingSprite = SKSpriteNode(imageNamed: "loading.png")
    loadingSprite.size = CGSize(width: 100, height: 100)
    loadingSprite.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
    loadingSprite.zPosition = 10
    self.addChild(loadingSprite)
    loadingSprite.runAction(SKAction.repeatActionForever(SKAction.rotateByAngle(3, duration: 0.5)))
    let qualityOfServiceClass = QOS_CLASS_BACKGROUND
    let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
    dispatch_async(backgroundQueue, {
        //Initialize the scene here!
        let scene = YourScene()
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.view!.presentScene(scene, transition: SKTransition.fadeWithDuration(1.0))
        })

    })
}
Epic Byte
  • 33,840
  • 12
  • 45
  • 93
  • I feel it is close :) But it still freezes first, loading sprite comes out, after that transition runs. But as I say, it still freezes first.. – white5tone Jun 27 '15 at 19:58
  • @BatıAktaş Ah I think I know what the problem is. Are you initializing your content inside the didMoveToView? My solution only works if you initialize all content in the Game Scene's initializer. – Epic Byte Jun 27 '15 at 20:01
  • Ah yes, exactly! So is there any other solutions to do that? – white5tone Jun 27 '15 at 20:03
  • You can try presenting the scene on the background thread. The only reason why I don't is for safety reasons. I'm not sure how safe it is to present a scene on the background thread. I know that on Mac OS X I got a crash, maybe on iOS it will work fine. – Epic Byte Jun 27 '15 at 20:03
  • The better solution is just to move your content creation to the game scene's initializer. After all, that's the purpose of an initializer. – Epic Byte Jun 27 '15 at 20:04
  • I moved all the content to game scene's initializer but result is still same :/ – white5tone Jun 27 '15 at 20:07
  • @BatıAktaş Can you describe again in detail what happens. When does it freeze and when is it working? – Epic Byte Jun 27 '15 at 20:08
  • I am pressing that 'start button'. It calls the "presenScene" function. When it calls that function, all the other animations stops (application is freezes), after 1 or 1.5 second of freeze, SKTransition runs and game scene comes out – white5tone Jun 27 '15 at 20:11
  • @BatıAktaş Can you maybe edit the question to post your presentScene function? I can try to take a look and see why it might not be working. – Epic Byte Jun 27 '15 at 20:14
  • in the first scene I just call "firstScene.presentScene(secondScene(size:CGSize))" function. But secondScene creates around 35-40 sprites. It looks like it takes a bit time to load them so everything freezes and while everything freezing the secondScene loads those sprites – white5tone Jun 27 '15 at 20:19
  • @BatıAktaş Ok, but are you using the code I posted above correctly. It should go like this. 1) Run your loading animation. 2) Initialize the second scene on background thread using the code I posted in answer. 3) Present the second scene using the code I posted in answer. Is that what you are doing? – Epic Byte Jun 27 '15 at 20:24
  • @BatıAktaş As your second scene gets initialized (all of its 35-40 nodes get created and added to the second scene) the loading animation should continue to animate. – Epic Byte Jun 27 '15 at 20:25
  • @BatıAktaş Hmm, well I don't know what could be the problem then. The only thing you can do is post some code and I can take a look. This approach works for my game so it should work for yours as well. – Epic Byte Jun 27 '15 at 20:32
  • @BatıAktaş Ah I see the problem. You aren't initializing the scene on the background thread at all. I'll update my answer to include the fix. – Epic Byte Jun 27 '15 at 20:34
  • @BatıAktaş I updated my answer. See, you are calling this method but your scene is already initialized when you call this method. You need to initialize your scene in this method but dispatch it onto the background thread. In the code I put a comment showing your where you should initialize your scene. – Epic Byte Jun 27 '15 at 20:41
  • Voila Epic Byte! You solved the problem, thank you very much! – white5tone Jun 27 '15 at 20:51
  • @BatıAktaş Awesome! Glad to hear you got it working. Good luck with your game :) – Epic Byte Jun 27 '15 at 20:52
0

Start the loadup code in a background thread (performSelectorInBackground), then show the animation from the main thread. The background thread will do its thing while the animation runs in parallel.

The background thread cannot directly update the animation, but it can periodically call the main thread (performSelectorOnMainThread) and have the main thread make updates.

When the background thread is done, call a mainthread function (performSelectorOnMainThread) that tells it to stop the animation and proceed with the next scene.

A similar questions that may be helpful: updating UIProgressBar progress during loop

Community
  • 1
  • 1
Thunk
  • 4,099
  • 7
  • 28
  • 47