The game loop

The game loop is a game developer's roadmap. The names differ depending on the framework and platform, but the same rules apply. The game loop comprises of all the methods, physics updates, and draw calls that occur during a single frame of your game and their order of execution. The golden rule to game development is to try to keep this loop always spinning in full iterations at no slower than 16.6 milliseconds, or 60 frames per second.

There are aspects of the game loop that don't have to be controlled by the game developer as much as they used to be in the past, though we do have the option to work down to the very GPU calls using OpenGL, or even better, Apple's Metal API. We will discuss more on these topics later on.

Here is what the SpriteKit game loop looks like:

The game loop

The preceding is an illustration given to us directly from the Apple Developer site. We see a number of functions that are called during a single frame. The first function iterated through is update(). The update() function is where we add most of our own game-specific updates and various checks on game objects (such as positions and character statuses).

The loop structure gives us the option to do updates after we know a certain set of tasks in the frame have happened, that's where didEvaluateActions(), didSimulatePhysics(), didApplyConstraints(), and didFinishUpdate() functions come in handy.

Note

Anyone coming from Unity might be familiar with its general game loop functions, such as Awake(), Start(), FixedUpdate(), update(), and LateUpdate(). The SpriteKit game loop allows some similar code/render flow, but as we'll see, there are some slight differences.

For more on the game loop and its functions, see the following link from the Apple documentation at https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Actions/Actions.html.

Utilizing the other game loop methods could make sure certain calls in your game don't go out of order and can even help with the important task of making the most out of each frame in a fast, efficient manner.

For instance, in the public game PikiPop, mentioned previously, here's how the game uses the game loop in its main GameScene.swift code:

//Update() Example
//From main GameScene.swift
override func update(currentTime: CFTimeInterval) {
        //Update player
        if(player?.isPlayable==true){
            player!.update(currentTime)
        }
    }

The preceding code first checks whether the player is playable with the isPlayable Boolean. This status can mean a number of things, like if the player is alive or not, is spawning, and so on. The game loop's update() function, which is being overridden from its parent update() function of the SKScene object, takes a parameter of the time utility type CFTimeInterval. CFTimeInterval is a special Core Foundation double type that measures time in seconds and thus updates the player object (if not null) during each interval.

As a brief summary of PikiPop, it's a procedural 2D side-scrolling game somewhat similar to the game Flappy Bird. Unlike Flappy Bird, Piki is able to traverse the game in all directions based on player taps and swipes. Piki could get trapped between the stage objects and the edge of the stage.

The game loop

The preceding image is Piki getting injured if pushed into the left-hand side of the screen.

Edges in that game's stages use SpriteKit's own special objects named SKConstraints. More on these later, but in short, they dictate the range and orientation SpriteKit sprites can take. Sprites in SpriteKit (both developer-defined objects, such as PikiPop's Player object and the default SKSpriteNode) are all derived from SKNode objects that work with SKConstraints and other physics-based framework functionality.

We could check whether Piki is being pushed against the corner in the update() part of the game loop, but since constraints are part of the framework's physics architecture, it's best to do this check during the didSimulatePhysics() portion of the render loop of SKScene as seen here:

override func didSimulatePhysics() {
    
    //run check on Player
    let block: (SKNode!, UnsafeMutablePointer<ObjCBool>) ->
	Void  = { node, stop in
        /*checks if the node is the player and is moved/crushed to the left by a physics object.  This is done by comparing the node's position to a position that is, in this case, less than 26% off the left side of the screen; calculated by multiplying the screen's width by 0.26  */
        if let playerNode = node as? Player{
            if (playerNode.position.x < self.frame.size.width*0.26 && playerNode.isPlayable) {
                playerNode.playerHitEdge()
            }
            
        }

    }


...more code

The first part of this code, let block: (SKNode!, UnsafeMutablePointer<ObjCBool>) -> Void = { node, stop in, is done in what's known as a block or a closure syntax, which Swift lets us do rather dynamically. Don't mind the details of this kind of code for the moment; just note that we check the player's position in x versus the edge of the window's frame in this portion of the game loop.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.174.253