How to Create an Interactive Children’s Book for the iPad

Learn how to create your own beautiful animated interactive children’s book for the iPad! By Tammy Coron.

Leave a rating/review
Save for later
Share
You are currently viewing page 5 of 5 of this article. Click here to view the first page.

Adding Page Two

The code for page two is roughly the same as that for page one; to this end, it's been pre-populated for you in Scene02.m. The code is heavily commented for your reading pleasure, and since it's very similar to Scene01.m it won't be covered in detail here.

One thing to note is that Scene02 has an instance variable — _catSound — that references an SKAction that plays a sound. This illustrates that you can store SKActions and reuse them, but it also improves the user experience in the case of actions that play sounds.

Your app loads the sound into memory when you create a sound action, so initializing the sound action before it's needed eliminates any potential pauses your users might experience.

Build and run your project; tap "Read Story" and use the navigation buttons to move back and forth in the story (after the text is done reading), like so:

tc_spritekit_build8

As an added bonus, tap on the cat to hear him meow!

Ok, enough messing around with pre-written code and kitties. Back to work, lazy pants! :]

Adding Page Three

Hopefully you enjoyed your short break to play with the kitty, but don't think that just because you didn't write the code for Page Two that it's not in your best interest to review it! There's lots to be learned by reviewing code written by others.

In the interest of keeping this tutorial focused, Scene03.m also provides a lot of the code you'll need, but there's still a little to add.

Add the following code to setUpMainScene in Scene03.m:

/* add the kid and the cat */
    
SKSpriteNode *cat = [SKSpriteNode spriteNodeWithImageNamed:@"pg03_kid_cat"];
cat.anchorPoint = CGPointZero;
cat.position = CGPointMake(self.size.width/2 - 25, 84);
    
[self addChild:cat];
    
/* add Snowflakes */
    
float duration = 1.25f; // determines how often to create snowflakes
[self runAction:[SKAction repeatActionForever:[SKAction sequence:@[[SKAction performSelector:@selector(spawnSnowflake) onTarget:self],[SKAction waitForDuration:duration]]]]];

Just as before, you create a new SKSpriteNode, set its anchorPoint and position and add it to the scene. Nothing surprising there.

Next you create an SKAction sequence that runs forever. You can use SKAction’s performSelector:onTarget: to run any method of your choosing. In this case, the action runs spawnSnowflake; you'll be writing that method in a moment.

The above sequence ends with a waitForDuration: action; since the sequence repeats forever, it calls spawnSnowflake, pauses for the specified number of seconds as stored in duration, then repeats those two actions forever.

Add the following code to spawnSnowflake in Scene03.m:

// here you can even add physics and a shake motion too
    
CGFloat randomNumber = RandomFloatRange(1, 4);
CGFloat duration = RandomFloatRange(5, 21);
    
NSString *snowflakeImageName = [NSString stringWithFormat:@"snowfall0%.0f",randomNumber];
SKSpriteNode *snowflake = [SKSpriteNode spriteNodeWithImageNamed:snowflakeImageName];
snowflake.name = @"snowflake";
    
snowflake.position = CGPointMake(RandomFloatRange(0, self.size.height), self.size.height + self.size.height/2);
[self addChild:snowflake];
    
SKAction *actionMove = [SKAction moveTo:CGPointMake(snowflake.position.x + 100, -snowflake.size.height/2) duration:duration];
    
SKAction *actionRemove = [SKAction removeFromParent];
[snowflake runAction:[SKAction sequence:@[actionMove, actionRemove]]];

The block of code above executes continuously because the SKAction calling this method was instructed to run forever. Talk about willing to make a commitment. Men, please take note. ;]

So what does that code actually do?

  1. It generates an SKSpriteNode using a random snowflake image.
  2. It creates and executes an SKAction sequence that includes an action to move the sprite down the screen using SKAction's moveTo: class method.
  3. Finally, it removes the sprite from the scene using SKAction's removeFromParent class method.
Note: This would be the perfect place to add some physics and a method that creates a snow globe effect when the user shakes the device. I'll leave that job to you, dear reader!

Build and run your project; you should see snowflakes start to appear and move down the screen, as shown below:

tc_spritekit_build9

Note: Just for fun, adjust the duration variable to 0.15. The value is inversely proportional to the number of snowflakes on the screen. Build and run your project and watch a blizzard unfold right before your very own eyes! When you're done creating the snowpocalypse, move along — that's enough playing in the snow for now!

Eagle-eyed readers will have noticed that the snowflakes run right over your footer. Time to fix that!

Add the following code to checkCollisions in in Scene03.m:

[self enumerateChildNodesWithName:@"snowflake" usingBlock:^(SKNode *node, BOOL *stop)
{
  SKSpriteNode *snowflake = (SKSpriteNode *)node;
  CGRect footerFrameWithPadding = CGRectInset(_footer.frame, -25, -25); // set padding around foot frame
         
  if (CGRectIntersectsRect(snowflake.frame, footerFrameWithPadding))
  {
    [snowflake removeFromParent];
  }
}];

Using enumerateChildNodesWithName:, you're able to detect nodes with the specified name. Since you gave each snowflake a node name of ‘snowflake’, you can do two things here: one, apply the collision detection on matching nodes only, and two, remove the node only if you detect a collision. You detect collisions using CGRectIntersectsRect.

The code above looks and works great, but how do you call it? How does the program know when to run it? That’s where the infamous "game loop" comes in handy. You may have noticed it already, but it's explained in detail below if you didn't follow through the code.

Sprite Kit uses a traditional rendering loop — often referred to as a game loop — to process the contents of each frame before its rendered and presented. Sprite Kit calls update: for each frame; it’s in this method that you will write the code to call the collision detection method you created above.

Add the following code to update: in Scene03.m:

[self checkCollisions];

Build and run your project; you now should see the snowflake sprites disappear as they approach the top edge of the footer, as shown below:

tc_spritekit_lastpage

Note: Collision detection is important in game development. For example, a routine like this would be useful to detect when your hero ship fired at an enemy ship in a space adventure game. If you detect a hit, then remove the enemy ship from the screen. In this tutorial, the collision detection is simplified, but the same basic principles apply.

Where To Go From Here?

At this point, the rest of the story is up to you!

Note that the Scene04.m file has been populated with a generic "to be continued" scene. I want you to create Page Four using everything you’ve learned in this tutorial. Here’s a mockup of what your page could look like:

tc_spritekit_comp

Everything you need is already included with the project. Have fun!

I hope you enjoyed working through this tutorial as much as I have enjoyed writing it. To compare notes, download the complete sample project here.

If you're looking to learn more about Sprite Kit, be sure to check out our book, iOS Games by Tutorials.

If you have any questions or comments, feel free to join in the discussion below!