An iOS 7 Sprite Kit Game Tutorial

From Techotopia
Jump to: navigation, search
PreviousTable of ContentsNext
An Introduction to iOS 7 Sprite Kit ProgrammingAn iOS 7 Sprite Kit Collision Handling Tutorial


Purchase the fully updated iOS 10 / Swift 3 / Xcode 8 edition of this book in eBook ($19.99) or Print ($45.99) format.
iOS 10 App Development Essentials Print and eBook (ePub/PDF/Kindle) edition contains over 100 chapters. Learn more...

Buy eBook Buy Print Preview Book


In this chapter of iOS 7 App Development Essentials, many of the Sprite Kit framework features outlined in the previous chapter will be used to create a game based application. In particular, this tutorial will demonstrate practical use of scenes, textures, sprites, labels and actions. In addition, the application created in this chapter will also make use of physics bodies to demonstrate the use of collisions and simulated gravity.




About the Sprite Kit Demo Game

The game created in this chapter consists of a single animated character that fires arrows across the scene when the screen is tapped. For the duration of the game, balls fall from the top of the screen with the objective being to hit as many balls as possible with the arrows. When an arrow hits a ball, the texture of the arrow is changed to make it appear as though the tip of the arrow is embedded in the ball. A physical join is also established at the point of collision so that the arrow sprite remains stuck into the side of the ball as it continues to fall off the bottom of the screen.

The completed game will comprise the following two scenes:

  • WelcomeScene – The scene which appears when the game is first launched. The scene will announce the name of the game and invite the user to touch the screen to begin the game. The game will then transition to the second scene.
  • ArcheryScene – The scene where the game play takes place. Within this scene the archer and ball sprites are animated and the physics behavior and collision detection implemented to make the game work.

In terms of sprite nodes, the game will include the following:

  • Welcome Node – An SKLabelNode instance that displays a message to the user on the Welcome Scene.
  • Archer Node – An SKSpriteNode instance to represent the archer game character. The animation frames that cause the archer to load and fire an arrow are provided via a sequence of image files contained within a texture atlas.
  • Arrow Node – An SKSpriteNode instance used to represent the arrows as they are shot by the archer character. This node is initially assigned a texture showing the entire arrow. This texture is then changed on collision with a ball to show the arrow embedded into the target. This node has associated with it a physics body so that collisions can be detected and to make sure it responds to gravity.
  • Ball Node – An SKSpriteNode used to represent the balls that fall from the sky. The ball has associated with it a physics body for gravity and collision detection purposes.
  • Game Over Node – An SKLabelNode instance that displays the score to the user at the end of the game.

The overall architecture of the game can be represented hierarchically as outlined in Figure 57-1:


The node hierarchy of the example iOS 7 Sprite Kit game

Figure 57-1


Creating the SpriteKitDemo Project

To create the project, launch Xcode and select the Create a new Xcode project option from the welcome screen (or use the File -> New -> Project…) menu option. On the template selection panel (Figure 57-2) make sure that the Application category is selected under iOS in the left hand pane before choosing the SpriteKit Game template option.


Selecting the Xcode 5 Sprite Kit Game project template

Figure 57-2


Click Next to proceed, enter SpriteKitDemo as both the product name and class prefix on the resulting screen and change the Devices menu to iPad. Click Next and choose a suitable location for the project files. Once selected, click Create to create the project.


Reviewing the SpriteKit Game Template Project

Selection of the SpriteKit Game template has caused Xcode to create a template project with a demonstration incorporating some pre-built Sprite Kit behavior. This consists of an SKView instance and a single SKScene child with a blue background and an SKLabelNode displaying text that reads “Hello, World!”.

The SKScene instance also includes a touchesBegan method implementation which, when triggered, creates an SKSpriteNode instance textured with the Spaceship.png image file and displays it at the location at which the screen was touched. A rotation SKAction is then created and run on the space ship sprite node so that the sprite spins in place. To see the template project in action (Figure 57-3), run it on a physical iPad device or the iOS simulator.


The template Xcode 5 Sprite Kit Spaceship demo

Figure 57-3


As impressive as this may be given how little code is involved, this bears no resemblance to the game that will be created in this chapter, so this functionality needs to be removed to provide a clean foundation on which to build. Begin, therefore, by selecting and deleting the following files from the project:

  • SpriteKitDemoMyScene.h
  • SpriteKitDemoMyScene.m
  • Spaceship.png

Having deleted the above files, edit the SpriteKitDemoViewController.m file and remove both the #import directive to the SpriteKitDemoMyScene.h file and the code to create and present the corresponding scene:

#import "SpriteKitDemoViewController.h"

@implementation SpriteKitDemoViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Configure the view.
    SKView * skView = (SKView *)self.view;
    skView.showsFPS = YES;
    skView.showsNodeCount = YES;
}

With these changes made, it is time to start creating the SpriteKitDemo game. Note that the showsFPS and showsNodeCount properties are left enabled in the above changes. This will cause diagnostic information about the frames per second rate and number of active nodes to be displayed on any child scenes. This is useful for tracking the performance of a game during the development process and should be removed once development is complete.

Creating the Game Scene Classes

As previously outlined, the first scene of the game is a welcome screen on which the user will tap to begin playing. Add a new class to the project to represent this scene by selecting the File -> New -> File… menu option. In the file template panel, make sure that the Cocoa Touch entry listed under iOS is selected in the left hand panel and then choose the Objective-C class template before clicking on Next. On the subsequent screen, name the class WelcomeScene and make it a subclass of SKScene before clicking on Next.

On the final screen, navigate to the project directory where you would like the files to be created before clicking on Create to add the new class to the project.

Repeat the above steps to add the second scene to the project. This scene should be named ArcheryScene and should also be subclassed from the SKScene class.

Implementing the Welcome Scene

The Welcome Scene is presented to the user when the application first launches. Some code therefore needs to be added to the viewDidLoad method of the view controller to make this happen. Edit the SpriteKitDemoViewController.m file to import the WelcomeScene.h file and then to add code to the viewDidLoad method to present the scene to the user:

#import "SpriteKitDemoViewController.h"
#import "WelcomeScene.h"

@implementation SpriteKitDemoViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Configure the view.
    SKView * skView = (SKView *)self.view;
    skView.showsFPS = YES;
    skView.showsNodeCount = YES;

    WelcomeScene *welcome = [[WelcomeScene alloc]
                initWithSize:CGSizeMake(skView.bounds.size.width,
                skView.bounds.size.height)];

    [skView presentScene:welcome];
}

Compile and run the application and note that a black scene appears and that diagnostic information reports that there are zero nodes currently active in the scene. It is now time to add some behavior to the WelcomeScene class. These steps involve changing the background color of the scene and then creating and displaying an SKLabelNode instance that displays a message to the user.

Begin by editing the WelcomeScene.m file and modifying it to import the ArcheryScene.h file and to add a private variable which will be used to track whether or not the scene has already been populated with content:

#import "WelcomeScene.h"
#import "ArcheryScene.h"

@interface WelcomeScene ()
@property BOOL sceneCreated;
@end

@implementation WelcomeScene

@end 

When a game moves to a new scene, that destination scene is notified of this event by a call to its didMoveToView method. This method now needs to be implemented in the WelcomeScene.m implementation file as follows:

#import "WelcomeScene.h"
#import "ArcheryScene.h"

@interface WelcomeScene ()
@property BOOL sceneCreated;
@end

@implementation WelcomeScene

- (void) didMoveToView:(SKView *)view
{
    if (!self.sceneCreated)
    {
        self.backgroundColor = [SKColor greenColor];
        self.scaleMode = SKSceneScaleModeAspectFill;
        [self addChild: [self createWelcomeNode]];
        self.sceneCreated = YES;
    }
}
@end

This method performs some very simple tasks. First it changes the background color of the scene to green (note the use of the SKColor class when working with colors in Sprite Kit as opposed to the UIKit UIColor class). The method then scales the scene so that it fills the entire view. A method named createWelcomeNode (which has not yet been implemented) is then called and the resulting node added to the scene. The sceneCreated variable is then set to indicate that the scene has been created.

The purpose of the createWelcomeNode method is to create a new SKLabelNode instance and configure it to be positioned in the center of the scene and to display some text to the user in a particular font and size. Remaining within the WelcomeScene.m file, add this method so that it reads as follows:

- (SKLabelNode *) createWelcomeNode
{
    SKLabelNode *welcomeNode = 
         [SKLabelNode labelNodeWithFontNamed:@"Bradley Hand"];

    welcomeNode.name = @"welcomeNode";
    welcomeNode.text = @"SpriteKitDemo - Tap Screen to Play";
    welcomeNode.fontSize = 44;
    welcomeNode.fontColor = [SKColor blackColor];

    welcomeNode.position = 
     CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));

    return welcomeNode;
}

Compile and run the application, at which point the Welcome Scene should appear as illustrated in Figure 57-4:


An initial iOS 7 Sprite Kit scene

Figure 57-4


Note that the diagnostic display now indicates the presence of a single node (the SKLabelNode instance).

Transitioning to the Archery Scene

Clearly having instructed the user to tap the screen in order to play the game, some code now needs to be written to make this happen. This behavior will be added by implementing the touchesBegan method in the WelcomeScene class. Rather than move directly to ArcheryScene, however, some effects will be added in the form of an action and a transition.

When implemented, the SKAction will cause the node to fade away from view whilst an SKTransition will be used to animate the transition from the current scene to the archery scene using a “doorway” style of animation. Implement these requirements by adding the following method to the WelcomeScene.m file:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    SKNode *welcomeNode = [self childNodeWithName:@"welcomeNode"];

    if (welcomeNode != nil)
    {
        SKAction *fadeAway = [SKAction fadeOutWithDuration:1.0];

        [welcomeNode runAction:fadeAway completion:^{
            SKScene *archeryScene = 
                [[ArcheryScene alloc]initWithSize:self.size];

            SKTransition *doors = 
                [SKTransition doorwayWithDuration:1.0];

            [self.view presentScene:archeryScene transition:doors];
        }
         ];
    }
}

Before moving on to the next steps, we will take some time to provide more detail on the above code.

From within the context of the touchesBegan method we have no direct reference to the welcomeNode instance. We do know, however, that when it was created in the createWelcomeNode method that it was assigned the name “welcomeNode”. Using the childNodeWithName method of the scene instance, therefore, a reference to the node is being obtained within the touchesBegan method as follows:

SKNode *welcomeNode = [self childNodeWithName:@"welcomeNode"]; 

The code then checks that the node was found before creating a new SKAction instance configured to cause the node to fade from view over a one second duration:

SKAction *fadeAway = [SKAction fadeOutWithDuration:1.0];

The action is then executed on the welcomeNode. A completion block is also specified to be executed when the action completes. This block creates an instance of the ArcheryScene class and an appropriately configured SKTransition object. The transition to the new scene is then initiated:

SKAction *fadeAway = [SKAction fadeOutWithDuration:1.0];

[welcomeNode runAction:fadeAway completion:^{
SKScene *archeryScene = 
      [[ArcheryScene alloc]initWithSize:self.size];

SKTransition *doors = 
      [SKTransition doorwayWithDuration:1.0];

[self.view presentScene:archeryScene transition:doors];

Compile and run the application. Once running, touch the screen and note that the label node fades away and the transition to the ArcheryScene takes effect. Once again, we are presented with a black scene that now needs to be implemented.


Preparing the Archery Scene

The initial preparation of the ArcheryScene class largely mirrors that of the WelcomeScene. Select the ArcheryScene.m file and modify it as follows to add some private variables and implement the didMoveToView method and import the WelcomeScene.h interface file:

#import "ArcheryScene.h" 
#import "WelcomeScene.h"
		
@interface ArcheryScene ()
@property BOOL sceneCreated;
@property int score;
@property int ballCount;
@end

@implementation ArcheryScene

- (void)didMoveToView:(SKView *)view
{
    if (!self.sceneCreated)
    {
        self.score = 0;
        self.ballCount = 40;

        [self initArcheryScene];
        self.sceneCreated = YES;
    }
}
@end

The above code initializes the score to zero and the number of balls to be released to 40 before calling another method named initArcheryScene which now needs to be implemented as follows within the ArcheryScene.m file:

- (void) initArcheryScene
{
    self.backgroundColor = [SKColor whiteColor];
    self.scaleMode = SKSceneScaleModeAspectFill;

    SKSpriteNode *archerNode = [self createArcherNode];

    archerNode.position = 
         CGPointMake(CGRectGetMinX(self.frame)+55, 
                CGRectGetMidY(self.frame));

    [self addChild:archerNode];
}

Within this method, the background color of the scene is set to white and the scene is scaled to fill the parent SKView area. Next, a method named createArcherNode is called. Once implemented, this method will create a new SKSpriteNode instance and assign a texture to it so that it appears as an archer with a bow and arrows ready to be launched at the targets.

The method then sets the position of the archer sprite so that it appears near the left hand edge of the scene before adding it as a child to the SKScene parent.

Purchase the fully updated iOS 10 / Swift 3 / Xcode 8 edition of this book in eBook ($19.99) or Print ($45.99) format.
iOS 10 App Development Essentials Print and eBook (ePub/PDF/Kindle) edition contains over 100 chapters. Learn more...

Buy eBook Buy Print Preview Book

Adding the Texture Atlas

Before textures can be used on a sprite node, the texture images first need to be added to the project. Textures take the form of image files and may be added individually to the Supporting Files folder of the project. For larger numbers of texture files, it is more efficient (both for the developer and the application) to create a texture atlas. In the case of the archer sprite, this will require twelve image files to animate the loading and subsequent shooting of an arrow. As such, a texture atlas will be used to store these animation frame images. The images for this project can be found in the sample code download which can be obtained from the following web page:

http://www.ebookfrenzy.com/web/ios7

Within the code sample archive, locate the folder named SpriteImages. Located within this folder is the archer.atlas sub-folder which contains the animation images for the archer sprite node.

To add the atlas to the project, drag and drop the archer.atlas folder into the Supporting Files folder in the Xcode project navigator panel so that it appears as shown in Figure 57-5:


A iOS 7 Sprite Kit texture Atlas loaded into Xcode 5

Figure 57-5


By default, the project should be configured to generate the texture atlas when the application is compiled. Verify that this is the case by selecting the project name at the top of the project navigator panel followed by Build Settings in the main panel. Enter spritekit deployment into the search field and make sure that the Enable Texture Atlas Generation option is set to YES (Figure 57 6) for the SpriteKitDemo target.


Enabling texture atlas generation in Xcode 5

Figure 57-6

Obtaining a Texture from the Atlas

When the archer sprite is first initialized it needs to be textured with the archer001.png file from the texture atlas. This takes place in the createArcherNode method which now needs to be implemented. This method will create a new SKSpriteNode object and reference the archer001.png texture file located in the texture atlas.

Remaining within the ArcheryScene.m file, implement this method as follows:

- (SKSpriteNode *)createArcherNode
{
    SKSpriteNode *archerNode = 
      [[SKSpriteNode alloc] initWithImageNamed:@"archer001.png"];

    archerNode.name = @"archerNode";
    return archerNode;
}

Perform a test run of the application and verify that the archer sprite now appears at the side of the scene as illustrated in Figure 57-7:


A sprite added to a Sprite Kit game scene

Figure 57-7

Preparing the Animation Texture Atlas

When the user touches the screen, the archer sprite node will launch an arrow across the scene. For the purposes of this example we want the loading and shooting of the arrow by the sprite character to be animated. The texture atlas already contains the animation frames needed to implement this (named sequentially from archer001.png through to archer012.png), so the next step is to write some code to implement the animation.

In the first instance, an array of the textures in the animation atlas needs to be created. Whilst it is possible to write code to manually reference each texture file, this would quickly become a cumbersome task for animations involving large numbers of textures. A more efficient approach is to write a for loop to iterate through the files in the atlas, assigning each file name to the texture array. Since this only needs to be performed once each time the scene is presented, this is best achieved within the initArcheryScene method.

Edit the ArcheryScene.m file and modify it as follows to declare and initialize the array:

#import "ArcheryScene.h"
#import "WelcomeScene.h"

@interface ArcheryScene ()
@property BOOL sceneCreated;
@property int score;
@property int ballCount;
@property NSArray *archerAnimation;
@end

@implementation ArcheryScene
.
.
.
- (void) initArcheryScene
{
    self.backgroundColor = [SKColor greenColor];
    self.scaleMode = SKSceneScaleModeAspectFill;

    SKSpriteNode *archerNode = [self createArcherNode];

    archerNode.position = 
       CGPointMake(CGRectGetMinX(self.frame)+55, 
          CGRectGetMidY(self.frame));

    [self addChild:archerNode];

    NSMutableArray *archerFrames = [NSMutableArray array];

    SKTextureAtlas *archerAtlas = 
	[SKTextureAtlas atlasNamed:@"archer"];

    for (int i = 1; i <= archerAtlas.textureNames.count; ++i)
    {
        NSString *texture = 
            [NSString stringWithFormat:@"archer%03d", i];

        [archerFrames addObject:[archerAtlas textureNamed:texture]];
    }

    self.archerAnimation = archerFrames;
}

The above code creates a temporary array named archerFrames before obtaining a reference to the archer texture atlas. A loop is then initialized based on the number of textures in the atlas. With knowledge of the naming convention of the image files, a texture file name is created and the textureNamed method of the SKTextureAtlas instance used to extract the texture with the corresponding name. The texture is then added to the archerFrames array. Once the array has been populated with the image names it is assigned to the archerAnimation array where it will be referenced later to animate the sprite node.

Animating the Archer Sprite Node

Now that an array of textures for the animation action has been created and initialized, code now needs to be written to perform the animation. Since this animation is triggered by a touch on the screen, this code needs to go in the touchesBegan method of the ArcheryScene class. Edit the ArcheryScene.m file and implement this method as follows:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    SKNode *archerNode = [self childNodeWithName:@"archerNode"];

    if (archerNode != nil)
    {
        SKAction *animate = [SKAction 
          animateWithTextures:self.archerAnimation 
          timePerFrame: 0.05];
        [archerNode runAction:animate];
    }
}

The method obtains a reference to the sprite node representing the archer character in the game, creates an SKAction object configured to animate the texture frames in the archerAnimation array and then runs the action on the archer node.

Run the application and touch the screen within the Archery Scene. Each time a touch is detected, the archer will run through the animation sequence of shooting an arrow.

Creating the Arrow Sprite Node

At this point in the tutorial, the archer sprite node goes through an animation sequence of loading and firing an arrow but no actual arrow is being launched across the scene. In order to implement this, a new sprite node needs to be added to the ArcheryScene. This node will be textured with an image of an arrow and will be placed to the right of the archer sprite at the end of the animation sequence. A physics body will be associated with the arrow and an impulse force applied to it to propel it across the scene as though shot by the archer’s bow.

Begin by locating the ArrowTexture.png file in the SpriteImages folder of the sample code archive and drag and drop it onto the Supporting Files folder in the Xcode project navigator panel. Next, add a new method named createArrowNode within the ArcheryScene.m file so that it reads as follows:

- (SKSpriteNode *) createArrowNode
{
    SKSpriteNode *arrow = 
      [[SKSpriteNode alloc] initWithImageNamed:@"ArrowTexture.png"];

    arrow.position = CGPointMake(CGRectGetMinX(self.frame)+100, 
      CGRectGetMidY(self.frame));

    arrow.name = @"arrowNode";

    arrow.physicsBody = 
      [SKPhysicsBody bodyWithRectangleOfSize:arrow.frame.size];

    arrow.physicsBody.usesPreciseCollisionDetection = YES;

    return arrow;
}

The code creates a new SKSpriteNode object, positions it to the right of the archer sprite node and assigns it the name arrowNode. A physics body is then assigned to the node, using the size of the node itself as the boundary of the body and enabling precision collision detection. Finally the node is returned.


Shooting the Arrow

In order to propel the arrow across the scene, a physical force needs to be applied to it. The creation and propulsion of the arrow sprite needs to be timed to occur at the end of the archer animation sequence. This can be achieved via some minor modifications to the touchesBegan method:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    SKNode *archerNode = [self childNodeWithName:@"archerNode"];

    if (archerNode != nil)
    {
        SKAction *animate = 
             [SKAction animateWithTextures:self.archerAnimation 
                       timePerFrame: 0.05];

        SKAction *shootArrow = [SKAction runBlock:^{

            SKNode *arrowNode = [self createArrowNode];

            [self addChild:arrowNode];
            [arrowNode.physicsBody applyImpulse:CGVectorMake(35.0, 0)];
        }];

        SKAction *sequence = 
             [SKAction sequence:@[animate, shootArrow]];

        [archerNode runAction:sequence];
    }
}

A new SKAction object is created, this time specifying a block of code to be executed. This run block calls the createArrowNode method, adds the new node to the scene and then applies an impulse force of 35.0 on the X axis of the scene. An SKAction sequence is then created comprising the previously created animation action and the new run block action. This sequence is then run on the archer node.

When executed with these changes, touching the screen should now cause an arrow to be launched after the archer animation completes. Note that as the arrow flies across the scene it gradually falls towards the bottom of the display. This is, of course, due to the effect of gravity imposed upon the physics body assigned to the node.

Adding the Ball Sprite Node

The objective of the game is to score points by hitting balls with arrows. Clearly, the next logical step is to add the ball sprite node to the scene. Begin by locating the BallTexture.png file in the SpriteImages folder of the sample code package and drag and drop it onto the Supporting Files section of the project navigator panel.

Next add the corresponding createBallNode method to the ArcheryScene.m file as outlined in the following code fragment:

- (void) createBallNode
{
    SKSpriteNode *ball = [[SKSpriteNode alloc] 
        initWithImageNamed:@"BallTexture.png"];

    ball.position = CGPointMake(randomBetween(200, self.size.width),
                                self.size.height-50);

    ball.name = @"ballNode";
    ball.physicsBody = 
       [SKPhysicsBody bodyWithCircleOfRadius:(ball.size.width/2)-7];

    ball.physicsBody.usesPreciseCollisionDetection = YES;

    [self addChild:ball];
}

This code creates a sprite node using the ball texture and then sets the initial position at the top of the scene but a random position on the X axis. The node is assigned a name and a physics body that is slightly less than the radius of the ball image (this will ensure that there is no gap when the arrow is made to stick into the ball in the next chapter). Precision collision detection is enabled and the ball node is added to the scene.

Before proceeding, add the following methods to facilitate the random number generation used in calculating the X coordinate of the ball sprite node:

static inline CGFloat randomFloat()
{
    return rand() / (CGFloat) RAND_MAX;
}

static inline CGFloat randomBetween(CGFloat low, CGFloat high)
{
    return randomFloat() * (high - low) + low;
}

Next, modify the initArcheryScene method to create an action to release a total of 40 balls at one second intervals:

- (void) initArcheryScene
{
    self.backgroundColor = [SKColor whiteColor];
    self.scaleMode = SKSceneScaleModeAspectFill;

    SKSpriteNode *archerNode = [self createArcherNode];

    archerNode.position =
         CGPointMake(CGRectGetMinX(self.frame)+55,
                CGRectGetMidY(self.frame));

    [self addChild:archerNode];

    NSMutableArray *archerFrames = [NSMutableArray array];

    SKTextureAtlas *archerAtlas =
        [SKTextureAtlas atlasNamed:@"archer"];

    for (int i = 1; i < archerAtlas.textureNames.count+1; ++i)
    {
        NSString *texture =
            [NSString stringWithFormat:@"archer%03d", i];
        [archerFrames addObject:[archerAtlas textureNamed:texture]];
    }

    self.archerAnimation = archerFrames;

    SKAction *releaseBalls = [SKAction sequence:@[
         [SKAction performSelector:@selector(createBallNode) 
                    onTarget:self],
         [SKAction waitForDuration:1]
    ]];

    [self runAction: [SKAction repeatAction:releaseBalls 
                               count:self.ballCount]];
}

Run the application and verify that the balls now fall from the top of the scene. Attempt to hit the balls as they fall by tapping the background to launch arrows. Note, however, that when an arrow hits a ball it simply bounces off:


Multiple sprites animated on an iOS 7 Sprite Kit game scene

Figure 57-8


The goal for the completed game is to have the arrows stick into the balls on collision and for a score to be updated for each hit. The steps to implement this behavior will be covered in the next chapter entitled An iOS 7 Sprite Kit Collision Handling Tutorial.

The balls fall from the top of the screen because they have been assigned a physics body and are subject to the simulated forces of gravity within the Sprite Kit physical world. To reduce the effects of gravity on both the arrows and balls, modify the didMoveToView method to change the current gravity setting on the scene’s physicsWorld object:

- (void)didMoveToView:(SKView *)view
{
    if (!self.sceneCreated)
    {
        self.score = 0;
        self.ballCount = 40;
        self.physicsWorld.gravity = CGVectorMake(0, -1.0);

        [self initArcheryScene];
        self.sceneCreated = YES;
    }
}

Summary

The goal of this chapter has been to create a simple game for iOS 7 using the Sprite Kit framework. In the course of creating this game topics such as using sprite nodes, actions, textures, sprite animations and physical forces have been put to practical use. In the next chapter, this game example will be further extended to demonstrate the detection of collisions and the use of physical joins.


Purchase the fully updated iOS 10 / Swift 3 / Xcode 8 edition of this book in eBook ($19.99) or Print ($45.99) format.
iOS 10 App Development Essentials Print and eBook (ePub/PDF/Kindle) edition contains over 100 chapters. Learn more...

Buy eBook Buy Print Preview Book



PreviousTable of ContentsNext
An Introduction to iOS 7 Sprite Kit ProgrammingAn iOS 7 Sprite Kit Collision Handling Tutorial