IntroductionWelcome| 00:04 | Hi! I am Todd Perkins.
| | 00:06 | Welcome to Building and
Monetizing Game Apps for iOS.
| | 00:10 | In this course, you will learn the ins
and outs of working with cocos2d to use
| | 00:14 | Xcode to build an iOS game.
| | 00:17 | The game is full-featured and
implements multi-touch Game Center leaderboards,
| | 00:24 | in-app purchases, iAds, and
many other features using cocos2d.
| | 00:28 | We will start with the basics,
| | 00:32 | learning how cocos2d works.
| | 00:33 | You'll learn the fundamental classes of
cocos2d, and you will use those classes
| | 00:39 | to build a full-featured game.
| | 00:42 | I hope you're ready for an exciting
experience building and monetizing game
| | 00:46 | apps for iOS.
| | Collapse this transcript |
| What you should know before watching this course| 00:00 | Due to the advanced nature of this
course, I highly recommend coming in with a
| | 00:05 | background in iOS experience.
| | 00:08 | You should be familiar with
Objective-C and feel very comfortable doing
| | 00:12 | object-oriented programming.
| | 00:14 | While you don't have to know every
Objective-C class, you should be familiar with
| | 00:19 | saving data to user defaults, NSString,
NSArray, and NSMutableArray, and working
| | 00:25 | with primitive data types
like integers and floats.
| | 00:28 | If all of those things sounded
familiar to you, great; you're ready to move
| | 00:31 | forward and get started.
| | 00:33 | If any of that sounded foreign to you,
I recommend looking at the Objective-C
| | 00:37 | and iOS courses in the Online Training Library.
| | 00:40 | It's best that you feel comfortable
with object-oriented programming and
| | 00:44 | Objective-C before moving
forward with this course.
| | 00:47 | Now if you feel
comfortable then you're ready to go.
| | Collapse this transcript |
| Using the exercise files| 00:00 | If you are a Premium subscriber to
lynda.com or have purchased this title on a
| | 00:04 | disc, then you have access to
the exercise files for this course.
| | 00:09 | Exercise files are organized by chapters.
| | 00:12 | Outside of all the chapters
is a folder called assets.
| | 00:15 | That folder contains all of the assets
for the projects we will be working with
| | 00:19 | as we build Mole Hit! application.
| | 00:21 | The individual chapters contain folders,
and those folders contain the start and
| | 00:26 | final versions of each project we
will be working on in a particular movie.
| | 00:31 | As you go throughout the course, you'll see
what files you need to open up on your screen.
| | 00:36 | If you have access to the exercise files,
don't worry; you can still follow along.
| | 00:40 | Throughout the course I'll explain
how you could set up your files in the
| | 00:44 | same way so that you could follow along and
build a similar application on your own.
| | 00:48 | So once your exercise files are set
up, you're ready to move forward with
| | 00:52 | building and monetizing an iOS game.
| | Collapse this transcript |
| | Fixing errors in Xcode 4.6 | Viewing the finished game| 00:00 | The game we are going to build in this
course is based on the free version of Mole It!
| | 00:04 | that you can find in the App Store.
| | 00:06 | So if you'd like to follow along,
feel free to download that game.
| | 00:11 | From the main menu, you'll see some
buttons at the bottom, such as Game Center,
| | 00:16 | More Games, and Skins.
| | 00:18 | Game Center will show a leaderboard
with all of the scores ranked from highest
| | 00:24 | to lowest, so that players can compete
with other players all around the world.
| | 00:29 | More Games shows a link to other games
created by my company, Wedgekase Games.
| | 00:34 | Skins enables you to choose between
different artwork sets of the game.
| | 00:38 | So you can click on the alien to
use the Jetpack Handyman skin based on
| | 00:43 | another game called Jetpack Handyman, or you can
click on the mole and use the standard moleskin.
| | 00:50 | Click to play the game.
| | 00:52 | So here you can tap on the various moles,
and you will see that the score goes up
| | 00:56 | as you tap them. And when you
miss a mole, a carrot disappears.
| | 01:01 | Once all the carrots are
gone, you get a game-over.
| | 01:04 | You will also notice
blue moles and yellow moles.
| | 01:08 | The blue moles take two taps, and the
yellow moles must be tapped simultaneously.
| | 01:15 | So once you get a game-over, you can choose
to play again or return to the main menu.
| | 01:20 | Some additional features of this game
that we will add later on are in-app
| | 01:24 | purchases to purchase the Jetpack
Handyman skin and we will add iAds so that you
| | 01:30 | can generate revenue while
people are playing your game.
| | 01:34 | So as you can see, we are going to
be building a full-featured game
| | 01:38 | throughout this course,
| | 01:39 | so I hope you're ready for a good time.
| | Collapse this transcript |
|
|
1. Getting to Know Cocos2dUnderstanding cocos2d| 00:00 | You may be wondering why I chose
cocos2d over all of the other alternatives
| | 00:04 | for making an iOS game.
| | 00:06 | There are two main reasons for that:
| | 00:08 | for one, cocos2d uses Xcode, which I
really like, and the second reason is
| | 00:13 | that cocos2d I've found is the easiest way
that you can create a full-powered iOS game--
| | 00:20 | in other words, it's the easiest to
understand and the easiest to learn over all
| | 00:24 | of the other alternatives.
| | 00:26 | So if you just start with Xcode without
cocos2d, the closest thing to creating a
| | 00:30 | game is the template for
the OpenGL ES application.
| | 00:34 | Now if you test this application in the
simulator, you'll see that all you get
| | 00:39 | is a square that moves up
and down--not very exciting.
| | 00:47 | Further, let's take a look at all of the code
it takes to make that square move up and down.
| | 00:52 | So if I scroll down in
TestViewController.m, you will see a lot of code, and it
| | 00:56 | will take a while to really
understand what's going on.
| | 01:01 | Now let's look at a cocos2d example.
| | 01:03 | Here is my cocos2d project.
| | 01:05 | The init method contains all of the
basic code to create the app, and you will
| | 01:09 | see that it's pretty easy to
understand, and you can kind of guess what it's
| | 01:12 | going to do before you even test the app.
| | 01:14 | I will just test the app right now, and we
will take a look at it in the simulator.
| | 01:17 | Again, if you don't have the template
installed, don't even worry about writing
| | 01:22 | the code or following along
for this; just watch my screen.
| | 01:24 | So all we have is Hello
World text on the screen.
| | 01:30 | It's not moving like the square,
but we do have a lot less code.
| | 01:33 | Let me show you that we can just
animate that just like the square moves with
| | 01:38 | one line of code. Granted it may be a
complex line of code, but it's one line of code.
| | 01:42 | So let's take a look at how easy it is to
move the label up and down with one line of code.
| | 01:47 | So all we do is run a command--
| | 01:49 | again, you don't have to worry about
following along with this; just watch my screen.
| | 01:52 | Send a message to that
label that says Hello World.
| | 01:56 | We tell it to run an action.
| | 01:57 | The action is something
that's going to go on forever.
| | 02:01 | So I type CCRepeatForever, an
actionWithAction, and the action is going to be
| | 02:06 | something that moves it
down and moves it back again.
| | 02:09 | So that's a sequence of different actions.
| | 02:12 | I am going to separate this on
different lines so it's a little easier to read.
| | 02:16 | I know I said it would be one line, but
technically this could obviously fit on one line.
| | 02:20 | I am just doing this for readability purposes.
| | 02:23 | So I tell it to move in one second, and
I will tell it to move down a hundred pixels.
| | 02:37 | This is an X-Y coordinate right here.
| | 02:39 | I'll just copy and paste
that line, and that's it.
| | 02:47 | I'll test this in the simulator, and
you'll see Hello World moving up and down.
| | 02:52 | Now that's not super impressive, but
keep in mind, that took one line of code
| | 03:01 | from the basic cocos2d template.
| | 03:04 | So it's clear that cocos2d is more
concise and easier to understand than just
| | 03:10 | starting with a blank OpenGL ES application.
| | 03:13 | To go back to my first
point, why I like cocos2d,
| | 03:16 | g
we get to use Xcode, so we have access to
all of the code hinting, code coloring,
| | 03:21 | and all the other features that make
it easy to create an iOS application.
| | 03:24 | So throughout this chapter, we will
start at the beginning and you'll learn how
| | 03:28 | to make basic gameplay elements using cocos2d.
| | Collapse this transcript |
| Downloading and installing cocos2d| 00:00 | Now let's take a look at downloading
and installing the cocos2d template.
| | 00:05 | You can find them at cocos2d-iphone.org.
| | 00:09 | At that site, I've clicked the
Download link and I've downloaded the
| | 00:11 | latest stable version.
| | 00:13 | So you can click to download it here.
| | 00:14 | Once you download it,
double-click the file to unzip it.
| | 00:20 | So you'll see that I have the
folder here in my Downloads folder.
| | 00:24 | In Terminal, which you can find in the
Utilities folder within your Applications
| | 00:28 | folder, change the directory to that
cocos2d directory by typing "cd" and a space.
| | 00:34 | Then click and drag the
cocos2d folder into Terminal.
| | 00:39 | Once you do that, press Enter
and the directory will be changed.
| | 00:42 | Now we'll install the templates by typing
"./install-templates.sh -u -f" and then press Return.
| | 00:55 | You will be able to tell that
Terminal is doing something like this.
| | 01:01 | It will take a few seconds and then
say Done at the bottom of the screen, and
| | 01:05 | from there you can close Terminal, and
the temples are installed successfully.
| | 01:08 | You can confirm that everything is
working by going to Xcode and then clicking
| | 01:13 | File > New > New Project.
| | 01:16 | In the New Project area, you should have
a section under iOS called cocos2d, and
| | 01:21 | in there you should have different
options for different cocos2d projects.
| | 01:25 | I'll choose cocos2d, click Next, create a
project called Test, save it on the Desktop.
| | 01:33 | Once it's created, I'll simply test it in
the simulator to make sure it's working.
| | 01:36 | If it's working properly, you should see
the simple Hello World app on the screen.
| | 01:47 | There it is!
| | 01:49 | So I'll quit the simulator, and now
we've successfully installed cocos2d.
| | Collapse this transcript |
| Understanding scenes, layers, and sprites| 00:00 | The basic building blocks of
cocos2d are scenes, layers, and sprites.
| | 00:05 | Scenes are managed by the
director, with a class name of CCDirector.
| | 00:11 | Think of the director as controlling
the main thing that you're seeing on
| | 00:14 | the screen at one time.
| | 00:15 | So for example, there may be
one scene called the Main menu.
| | 00:19 | The cocos2d class for that is called CCScene.
| | 00:22 | Think of CC in cocos2d being short for coco.
| | 00:26 | So you may have another scene called Game.
| | 00:29 | So the director would control whether
you're looking at the Main menu or the game.
| | 00:34 | Scenes can contain layers and sprites.
| | 00:38 | A sprite is a visual object,
like the mole here on the screen.
| | 00:42 | So a scene can contain sprites.
| | 00:45 | It can also contain layers.
| | 00:47 | Layers can contain their own sprite as well.
| | 00:50 | So if you look here, the red bounding box shows
the CCLayer (blueMoles), which has three moles.
| | 00:57 | One of those is a sprite named
blueMole, which you can see with the
| | 01:02 | green bounding box.
| | 01:04 | So let's take a look at what scenes,
layers, and sprites would look like in code.
| | 01:09 | Here I have a blank cocos2d template
project called ScenesLayersSprites and an
| | 01:15 | AppDelegate.m. I am going to scroll down to
the bottom of applicationDidFinishLaunching.
| | 01:20 | You'll notice as you scroll down that
you will see the director is initialized.
| | 01:24 | So we access that
sharedDirector instance. It has a GL view.
| | 01:31 | This is all stuff that's written for you
and you'll probably never have to mess with.
| | 01:35 | At the very bottom of that method
you will see CCDirector sharedDirector
| | 01:39 | runWithScene, and then
HelloWorldLayer scene is passed in.
| | 01:44 | So the runWithScene method
enables you to switch between scenes.
| | 01:48 | So let's go to the HelloWorldLayer scene,
which we can find at HelloWorldLayer.m.
| | 01:53 | Let's take a look at the Scene method first.
| | 01:56 | Scene creates a blank CCScene,
which is accessed by the node method.
| | 02:04 | The node method turns an allocated,
initialized, and auto-released object.
| | 02:10 | This applies for layers, sprites, and scenes.
| | 02:14 | So it's a quick way to
create an auto-released object.
| | 02:17 | So we create a scene, and we create an
instance of HelloWorldLayer, add the
| | 02:23 | HelloWorldLayer to the
scene and return the scene.
| | 02:29 | Note that you don't have to run it like this.
| | 02:32 | The cocos2d template does because a
CC layer already has touch functionality
| | 02:37 | built-in, but usually when I create a
project I just have it run the node of the
| | 02:41 | main scene I want to run.
| | 02:43 | So we will take a look at
how that looks later on.
| | 02:45 | So in the init method we can
see sprites added to the screen.
| | 02:48 | An example of a sprite is a CCLabelTTF.
| | 02:53 | So that's a visual object
that we place on the screen.
| | 02:55 | We add it to the screen
using the addChild method.
| | 02:59 | If you've ever used Flash in
ActionScript, you might be familiar with the
| | 03:04 | addChild method already.
| | 03:05 | It works in the exact same way with cocos2d.
| | 03:08 | Each child you add is added in front of
the previous child, unless you specify a
| | 03:14 | Z position, so you can
control layering between sprites.
| | 03:18 | So to recap, cocos2d classes start
with CC, the director manages scenes
| | 03:23 | which are different organized parts
of your game, and scenes can contain
| | 03:27 | layers and sprites.
| | 03:29 | Sprites are visual objects and
layers are groups of sprites.
| | Collapse this transcript |
| Positioning sprites| 00:00 | cocos2d uses a bottom-left X-Y origin.
| | 00:04 | So the bottom-left position is at 0 X
and 0 Y, since the point system on the
| | 00:10 | iPhone goes from 0 to 480 horizontally
and 0 to 320 vertically, and we have X at
| | 00:20 | 0, Y at 320 at the top left, X at 480, Y
at 320 at the top right and X at 480, Y
| | 00:27 | at 0 at the bottom-right.
| | 00:28 | Keep in mind too that when you're
working with retina display, the coordinate
| | 00:31 | system does not change.
| | 00:32 | This is again because the coordinate
system is based on points and not pixels.
| | 00:37 | So let's take a look at positioning a sprite.
| | 00:40 | So we have a sprite on the screen
here and its X-Y origin is in the center.
| | 00:45 | So if you don't mess with its position,
its X position is 0 and its Y position
| | 00:50 | is 0, which puts the sprite at
the bottom left of the screen.
| | 00:54 | So if you wanted to move it to the top,
you would set its X to 0 and its Y
| | 01:00 | to 320; to the top-right would be X 480, Y
320; and the bottom-right would be X 480, Y 0.
| | 01:06 | So let's take a look at that in code.
| | 01:09 | I'm going to go to HelloWorldLayer.m.
Now this is just the default cocos2d template.
| | 01:17 | So what I'm going to do is erase all the code
inside of the if statement in the init method.
| | 01:22 | Now the first thing that we need to
do is to get a sprite on the screen.
| | 01:26 | To do that, we will need a file to load in.
| | 01:29 | Now I've already dragged in the
assets folder here in the resources
| | 01:32 | folder, you'll see.
| | 01:33 | If you don't have access to this, then you
can just import any PNG file into your app.
| | 01:40 | So I am just going to open up mole.png,
and that looks like exactly what I want.
| | 01:45 | So back in my code, I am going to
create a sprite by typing CCSprite.
| | 01:51 | Remember, everything has
that CC prefix. Asterisk.
| | 01:56 | We'll call this mole.
| | 01:57 | We will set it equal to, in brackets, CCSprite.
| | 02:02 | Now to get auto-released objects in
cocos2d, you can almost always use a class method,
| | 02:07 | so that saves you a lot of time;
| | 02:09 | you don't have to allocate most objects.
| | 02:11 | So CCSprite, and then I'm going to
call sprite with file and just pass in an
| | 02:16 | NSString for mole.png.
| | 02:19 | That's really all there is to it.
| | 02:20 | So you create the mole in memory, and
then you have to add it as a child so it
| | 02:26 | appears on the screen.
| | 02:27 | So in order to see anything visually, it
needs to be the child of some other object.
| | 02:33 | So on the next line, in brackets, self addChild:mole.
| | 02:39 | Now before you test the app in the simulator, I
want you to guess where it's going to appear.
| | 02:47 | Keep in mind it has a default X and Y of (0,0).
| | 02:52 | There it is, the bottom-left.
| | 02:54 | Did you guess right?
| | 02:57 | Let's look at changing the position.
| | 02:59 | So let's say I want to make it
100 X and 100 Y. Simple, mole.position.
| | 03:05 | You could do this before or
after addChild; that's fine.
| | 03:08 | Then in cocos2d we always set the
X and Y position at the same time,
| | 03:13 | so set it equal to CCP, which
takes an X and Y coordinate.
| | 03:18 | Now CCP is actually just a shortcut for
CGPointMake, a little shorter than CGPointMake.
| | 03:26 | So I prefer using ccp.
| | 03:29 | So in parentheses, after ccp--keep in
mind that's lowercase--type in (100, 100).
| | 03:35 | So we put this in X and Y of 100, and
that will align the middle of the mole
| | 03:40 | with an X and Y of 100.
| | 03:41 | So test it again and took a look at
the simulator. There we go!
| | 03:49 | So that's about it.
| | 03:52 | If you look right here in the center of
the mole, that's just about 100 pixels
| | 03:58 | up and 100 pixels to the right.
| | 04:00 | I am judging by it being
about a fourth of the screen size.
| | 04:07 | Also, keep in mind that the position
of the mole is based on the size of the
| | 04:11 | full PNG file and not the
size of the artwork itself.
| | 04:15 | So in this case the size of the file is a
little bit bigger than the actual area of mole,
| | 04:20 | so just keep that in mind.
| | 04:22 | Now let's say we wanted to put the
mole at the center of the screen.
| | 04:25 | Now we could do 480x320
divided by 2, which would be 240,160.
| | 04:30 | We can test, and there is the
mole in the center. Nice!
| | 04:43 | Close the simulator.
| | 04:45 | But what if we design this for the iPad?
| | 04:47 | Remember, the iPad has not just a
different resolution, but a different aspect
| | 04:51 | ratio from the iPhone,
| | 04:53 | so this wouldn't work right.
| | 04:55 | We would need some kind of variable
that represents the whole width and whole
| | 04:58 | height of the screen.
| | 04:59 | So to get that, above the
mole, create a CGSize object.
| | 05:03 | We will just call it s, no asterisk,
and we will set it equal to, in brackets,
| | 05:11 | I am going to type an extras set of
brackets and type "CCDirector sharedDirector"
| | 05:18 | and then in the outer brackets, "winSize."
| | 05:21 | So that gives me a width
and a height of the screen.
| | 05:25 | So I could change 240 to s.width,
divided by 2 and change 160 to s.height
| | 05:32 | divided by 2, and test the
app again in the simulator.
| | 05:36 | You will see that the mole is again in
the center of the screen. There we go!
| | 05:43 | So whatever size your display is, you
can get its width and height through the
| | 05:49 | director's winSize property.
| | 05:51 | So to recap, cocos2d uses X-Y
coordinates that start at the bottom-left, and
| | 05:57 | objects, like sprites, have the
registration point, or X-Y origin, in the center.
| | Collapse this transcript |
| Adjusting basic sprite properties| 00:00 | Now we'll take a look at the most
common sprite properties that you'll be
| | 00:03 | adjusting. I'm in
HelloWorldLayer.m, in the init method.
| | 00:08 | So we have the mole on the screen at center.
| | 00:10 | Now let's add a background.
| | 00:12 | So I'm going to type CCSprite, and we'll
call this bg, and we'll initialize it to
| | 00:18 | CCSprite spriteWithFile.
This is going to be called bg.png.
| | 00:22 | Then I'll simply add it to the stage.
| | 00:25 | So self addChild:bg.
| | 00:29 | Let's see what we get in the simulator.
| | 00:30 | Now keep in mind that the background
file is the whole size of the screen,
| | 00:37 | so where do you think it's going to show
up on the screen when the application loads?
| | 00:41 | The answer is that the center of the
background will be aligned with the bottom
| | 00:45 | left of the screen.
| | 00:46 | You'll also notice that the
background is covering up the mole.
| | 00:50 | So we want it to do two things here.
| | 00:52 | We want to put the background
behind the mole, for one, and then have the
| | 00:56 | background to be centered as a second thing.
| | 00:59 | So we'll close the simulator and then
in the addChild method that we called, type
| | 01:04 | a space, and another
method includes a Z position.
| | 01:09 | This is an integer, so I can type in -1.
| | 01:13 | So everything is at 0 by default,
and as you add more children, they
| | 01:17 | automatically get placed in front
of other objects if you don't tell it
| | 01:21 | specifically what z position to be at.
| | 01:24 | So by passing in z at -1, then we
put the background behind the mole.
| | 01:29 | Now we want to position it
in the center of the screen.
| | 01:32 | I mentioned earlier that the
background is the same size as the screen, so we
| | 01:37 | could have it centered just like the
mole and it would be in the center. Or we
| | 01:41 | can look at another option,
which is to change its anchor point.
| | 01:45 | Remember, the default anchor
points of objects are in the center.
| | 01:50 | So we could shift that to be
anywhere we want on the object.
| | 01:54 | Let's take a look at how that works.
| | 01:57 | Go right below the line where we
create the background and then type
| | 02:00 | bg.anchorPoint, and we set
this using a coco point as well.
| | 02:06 | So ccp. And here it's not coordinates,
but it's a percentage. So it's from 0 to 1.
| | 02:15 | So 0 would be, the anchor point would
be set at the left of an object for the
| | 02:19 | first value and 1 would be
all the way at the right.
| | 02:22 | So the default is .5 for X and .5
for Y. That's right in the center.
| | 02:28 | So if we wanted to change the anchor point
to say the bottom-left, it would be (0, 0).
| | 02:34 | So when you do that the default
position is going to be at 0, 0, which is going
| | 02:39 | to align the bottom-left of the
object at the bottom-left of the stage.
| | 02:44 | And since the background is the same size as
the screen, it's going to fill the whole screen.
| | 02:49 | So let's test the app in
simulator. There we go.
| | 03:02 | Now let's take a look at some
other properties that we can modify.
| | 03:04 | So we've already looked at position and
anchor point, so let's take a look at rotation.
| | 03:08 | So right under where we set the mole
position, type "mole.rotation" and here you
| | 03:14 | can just set a value between 0 and 360.
| | 03:18 | So let's say I set its rotation to 180.
| | 03:21 | We'll test. See what we get.
| | 03:23 | Now the mole is upside down.
| | 03:28 | So you can mess with rotation if you
ever want to adjust that on an object.
| | 03:35 | There's also scale, a value between 0
and 1--0 being 0% scale and 1 being 100--
| | 03:44 | or you can go past 1.
| | 03:45 | So what I'm going to do is just type in
.25 and then test the app.
| | 03:51 | There we go. It's a tiny, little mole.
| | 03:59 | Note that you can change
scale X and scale Y independently.
| | 04:02 | So if I change scale to scaleX and test
the app again in the simulator, you'll
| | 04:07 | see the mole only scales on the horizontal axis.
| | 04:11 | Remember that scaling is
based on the anchor point as well.
| | 04:14 | So with anchor point in the center, the
mole will scale to the center. The mole
| | 04:18 | will rotate from the center.
| | 04:19 | But if you alter the anchor point like
we did for the background, it will rotate
| | 04:24 | or scale around that anchor point.
| | 04:25 | So keep that in mind.
| | 04:29 | You can adjust the Opacity, so I'll
change scale X to opacity. And this is
| | 04:34 | between 0 and 255, so if I give it
a value of 100, the mole should be about
| | 04:41 | halfway transparent. There we go.
| | 04:48 | And if you want to hide and show an
object, you can change its visible property.
| | 04:53 | So I'll change opacity to visible, and
this is just YES or NO, so I'll change
| | 04:57 | that to NO and you won't
see the mole on the screen.
| | 05:06 | The visible property works great for
memory optimization. So if you just want to
| | 05:10 | show and hide objects, always use
visible over opacity. That's because even a 0%
| | 05:17 | opaque object still has to be drawn,
and the visible objects are not drawn and
| | 05:23 | thus don't take up memory
while your app is running.
| | 05:26 | So just keep that in mind.
| | 05:28 | Those are the basic properties that
we'll be using throughout this course.
| | 05:31 | So remember, you can set the position, and by
default an object's anchor point is in the center.
| | 05:38 | You can adjust the anchor
point using percentages, from 0-1.
| | 05:42 | You can also adjust rotation, scale--on
the X and Y axis--opacity, and visibility,
| | 05:49 | all using dot syntax.
| | Collapse this transcript |
| Handling touches| 00:00 | Nearly every game needs
some way to handle touches.
| | 00:05 | For example, in the mole game that
we're making, we'll need to detect if you
| | 00:09 | tapped a mole when you touch the screen.
| | 00:12 | Let's take a look at
handling touches in cocos2d.
| | 00:15 | Right inside the if statement of the
init method in HelloWorldLayer.m, I'm going
| | 00:20 | to type self.isTouchEnabled = YES.
| | 00:25 | This one line of code sets this
layer as a delegate of a touch.
| | 00:30 | So once you do that, you can
then respond to the touch events.
| | 00:34 | So scroll down below the init method,
and here we'll handle that touch event by
| | 00:40 | typing -(void) ccTouchesBegan.
| | 00:49 | So I want you to just complete that
method, TouchesBegan, which is an NSSet of
| | 00:54 | touches with the event. And here the
first thing we're going to do is just log
| | 01:00 | that a touch occurred. So type CCLOG.
| | 01:01 | I like to use CCLOG to log things
that happen into the Output window because
| | 01:08 | this code doesn't do
anything if you run in Release mode,
| | 01:12 | so only in Debugging mode does this code run.
| | 01:15 | So it's like an NS log but just more efficient.
| | 01:18 | You don't have to worry that if you
forget to comment any out that they are
| | 01:23 | trying to run in the
released version of your game.
| | 01:26 | So in here what I'm going
to do is log "touch happened!"
| | 01:32 | So we'll test this out and take a look
at what it looks like in the simulator.
| | 01:40 | So I can click anywhere, and in the
Output window you should see that message.
| | 01:46 | So I'm going to scroll down to the bottom and
you'll see that touch happened! occurs many times.
| | 01:51 | Now what if we wanted more
information about that touch, like where it was?
| | 01:56 | So right above CCLOG we're going
to create a new line of code.
| | 02:00 | So what I'm going to do is type
UITouch, and I'm going to just grab any touch.
| | 02:04 | So we'll call this touch, and we're
going to set it = touches anyObject.
| | 02:11 | On the next line create a CGPoint,
call it location, and I'll set it =
| | 02:20 | touch locationInView--and this is in
brackets--and then some more brackets
| | 02:27 | after locationInView: touch view.
| | 02:29 | So we're getting its location, and then
we need to convert this point to a GL
| | 02:35 | point so it will go with
our cocos2d coordinates.
| | 02:39 | So we'll do it on the next line. location =,
double brackets CCDirector sharedDirector,
| | 02:47 | and inner brackets, convertToGL, and pass in location.
| | 02:52 | Now here we have an X-Y coordinate
for the touch which we can access.
| | 02:57 | So in the CCLOG, I'm going to
change touch happened at x: %0.2f--
| | 03:01 | that will give us a float--and then a comma y:
| | 03:07 | %0.2f. And then after the closed quotes,
I'm going to type location.x and then
| | 03:17 | location.y. Save and test.
| | 03:26 | So in the Output window, now I should get
the location of the touches that happened.
| | 03:31 | So touch a few times at the
top-right, then at the bottom-left.
| | 03:33 | We'll quit the simulator, and we'll see what
we get in the Output window. There we go.
| | 03:41 | So now we can access the X-Y coordinates
of a touch location all over the screen.
| | 03:46 | So remember, to implement touch
functionality, you can call self.isTouchEnabled,
| | 03:53 | set it to YES on a layer, and
then you just need to implement the
| | 03:58 | ccTouchesBegan event handler.
| | Collapse this transcript |
| Working with tags| 00:00 | Along with handling touches in a
game, it's necessary to know if a
| | 00:04 | certain object was touched.
| | 00:06 | Let's take a look at how we can
detect if the mole was touched.
| | 00:10 | So one way to do that would be to
declare the mole in our header file and have
| | 00:15 | it as a property used throughout our
class. But the shortcut is to use tags.
| | 00:21 | So when I call self.addChild:mole, I
can add in the z position, and note that I
| | 00:26 | can also add in z the position and a tag.
| | 00:29 | You can also add a tag after the fact.
| | 00:31 | So after self.addChild:mole, I could
type mole.tag =, and I could set this to 1,
| | 00:39 | for example--so just any integer will do here.
| | 00:42 | Now I recommend using some kind of
enumerated value if you're going to use this,
| | 00:46 | so you don't have to remember the
number every single time you recall it,
| | 00:50 | so just keep that in mind. And scroll
down to ccTouchesBegan. And right above the
| | 00:56 | LOG statement, I'm going
to create an if statement.
| | 00:59 | I'm going to see if the mole was touched.
| | 01:01 | So in if statement I'll type
CGRectContainsPoint. And the first thing we need is a rect.
| | 01:08 | That's a rectangle.
| | 01:09 | Now the rectangle is going to be the
bounding box of the mole. So in here I'll
| | 01:16 | type some brackets, and I'll type some
inner brackets, and in the inner brackets we'll
| | 01:21 | type self getChildByTag, and the tag is
going to be 1. And in the outer brackets
| | 01:28 | I'm just going to type boundingBox.
| | 01:29 | So let's get in that point, and then
the point I want to check against is the
| | 01:34 | location of the touch, which we
already has saved in our location variable.
| | 01:39 | So if the rectangle, which is the
bounding box of the mole, contains the touch
| | 01:45 | location, then the mole was touched.
| | 01:48 | So I'm just going to cut and paste the
CCLOG statement into that if statement.
| | 01:55 | So the only time we should see
it is if the mole was touched.
| | 01:59 | So, let's test this in the
simulator and see how it works.
| | 02:07 | Again, keep in mind that the bounding
box of the mole is a little bit bigger
| | 02:10 | than the mole itself, just because
of the way that I designed the file.
| | 02:14 | So if you want to click away from the
mole, just click all the way at the left or
| | 02:18 | right edge of the stage.
| | 02:19 | So I'll click a whole bunch of times on
the right, a whole bunch of times on the
| | 02:23 | left, and then I'm going to
click twice right on the mole.
| | 02:26 | I'll close the simulator and
then look in the Output window.
| | 02:32 | I should see that statement only occurring
twice in the Output window, and there you have it.
| | 02:38 | So we have successfully
detected if an object was touched.
| | 02:41 | So using tags, you can access sprites
without having to save them as properties.
| | 02:48 | So that's your call whether you do
that or not, but tags are a quick and easy
| | 02:52 | way to access the sprites.
| | 02:54 | Then, in the TouchesBegan event, you can
check to see if a touch is touching one
| | 02:59 | of your objects by using the
CGRectContainsPoint method.
| | 03:03 | The bounding box of your sprite can be
used for the rectangle, and the location
| | 03:06 | of the touch can be used for the location.
| | Collapse this transcript |
| Accessing accelerometer data| 00:00 | Some games use
accelerometer data as a source of input.
| | 00:03 | Let's look how to implement
accelerometer data into your game.
| | 00:07 | Keep in mind the simulator
doesn't get accelerometer data,
| | 00:10 | so this is just something where you could
see and use by testing on your own device.
| | 00:14 | So in the init method, I'm going
to change self.isTouchEnabled to
| | 00:18 | self.isAccelerometerEnabled, and I'll set it to YES.
| | 00:23 | And then I'll handle the
accelerometer event, which is void, and then it's
| | 00:28 | accelerometer didAccelerate.
| | 00:30 | So you should get that with code hinting;
| | 00:33 | if not, you can copy it
from my code on the screen.
| | 00:35 | And here, all you have to do is set the
X or Y position of the mole or any other
| | 00:41 | object based on the
acceleration of the accelerometer.
| | 00:45 | You can access that through
acceleration.x, .y, or .z. So those handle the
| | 00:53 | acceleration on the
different axes of the device.
| | 00:57 | To make it work for your game,
you'll just have to experiment a little bit.
| | 01:00 | I recommend trying to move
around the mole on your device with
| | 01:04 | acceleration values.
| | 01:05 | So again, to handle the accelerometer
input, set isAccelerometerEnabled to YES
| | 01:12 | on the layer you want to handle
and then handle the accelerometer
| | 01:17 | didAccelerate event.
| | 01:18 | You can access all of the
accelerometer data through the acceleration
| | 01:22 | value passed in.
| | Collapse this transcript |
| Understanding cocos2d actions| 00:00 | If you look at the top-selling iOS
games, you'll see animations everywhere:
| | 00:05 | character animations, even
the menus animate all the time.
| | 00:09 | Let's take a look at how to do some
basic animations using cocos2d actions.
| | 00:15 | Actions allow you to animate things
scaling up, or scaling down, rotating,
| | 00:21 | moving--basically any property
that a sprite has can be animated.
| | 00:26 | You can even have a delay and
then run a function if you want.
| | 00:30 | So let's take a look at how that works.
| | 00:32 | I am going to go down into
ccTouchesBegan, and I have here a CCSprite called
| | 00:38 | mole that I used to hold the object
with the tag of 1, which is the mole that we
| | 00:44 | created in the init method.
| | 00:45 | So let's say we wanted the mole to scale
up a little bit every time we clicked it,
| | 00:52 | but we wanted that to happen in an animation.
| | 00:55 | So in brackets, in the if statement,
type mole runAction, and then in
| | 01:00 | brackets, type CCScaleBy, and
then type a space and then type
| | 01:07 | actionWithDuration and scale.
| | 01:10 | Make sure to pick that one.
| | 01:11 | Now I'll go for the code hinting.
| | 01:13 | I'll have the time be 0.25, which is
a quarter of a second, and I'll have
| | 01:19 | the scale be 1.1 and then test it out in
simulator. And each time you click on the mole,
| | 01:25 | he should animate bigger and bigger and bigger.
| | 01:29 | So click on the mole, it scales up a
little bit. And notice he is not
| | 01:35 | just appearing bigger; it's animating.
| | 01:42 | The mole is pretty huge right there.
| | 01:43 | So using runAction, you can
virtually animate any editable property.
| | 01:49 | Let's just change the CCScaleBy to a CCMoveBy.
| | 01:55 | Notice that there's also MoveTo.
| | 01:57 | So the difference between By and To is that
By doesn't care about a starter end location;
| | 02:03 | it just says, "move an object in this
amount" and To says, "move an object to
| | 02:09 | this specific amount."
| | 02:10 | So if an object is at position 0, 0 and
use MoveBy, you pass in 0 for the X, 100
| | 02:18 | for the Y, it'll shift up and
just set the amount of 100 points.
| | 02:22 | So let's use CCMoveBy, and
we'll call actionWithDuration.
| | 02:25 | Let's have 1, so it will
be 1 second, and then ccp.
| | 02:32 | So if you wanted to move left or
right or up or down, you'd pass that in here.
| | 02:36 | So it will move in just the
amounts that you pass into ccp call.
| | 02:40 | So if I type in -10, 0, he will
only move to the left when I click it.
| | 02:46 | So let's test that out.
| | 02:55 | So we'll see him sliding to the
left a little bit each time I click.
| | 03:06 | So you'll also find in there CCFadeTo,
CCFadeBy, CCRotateTo, CCRotateBy, and
| | 03:14 | use them all in the same way:
| | 03:16 | you run the class method,
actionWithDuration, and then you modify another property.
| | 03:21 | So there is some extra parameter that
you pass into modify the rotation or the
| | 03:27 | scale, what have you.
| | 03:29 | Let's take a look at
running a sequence of actions.
| | 03:32 | Let's say when you click on the mole
you want him to scale up and then scale back down.
| | 03:35 | So I am going to delete the CCMoveBy,
type some brackets, and then type
| | 03:43 | CCSequence, and type actions.
| | 03:48 | This is going to be actions separated by commas.
| | 03:52 | So let me type some brackets.
| | 03:54 | I am going to push those brackets on
the next line and then push nil on the
| | 03:58 | next line so I can easily
run the sequence of actions.
| | 04:01 | So CCScaleTo actionWithDuration, have
this last a quarter of a second. And the
| | 04:11 | scale will be 1.1, and we'll just copy
and paste that line of code onto the next
| | 04:16 | line and then change 1.1 to 1.0, and that's it.
| | 04:24 | So we'll test the app, and in the
simulator, when we click on the mole, we should
| | 04:28 | scale up and then back down pretty quick.
| | 04:30 | So each time you click on him, he
scales up. And of course, you can list as
| | 04:43 | many actions as you want, so if you want
the mole to scale up and then scale down
| | 04:48 | and then call a function or to wait a
certain amount of time, it's easy to do.
| | 04:53 | To wait time, you use
CCDelayTime actionWithDuration.
| | 04:59 | You just pass in how long you want it
to wait before the next action. And then
| | 05:03 | you could also do calling a function
by CCCallFunc, and then you just pass in
| | 05:10 | actionWithTarget and selector.
| | 05:12 | So that way you can make something happen
and then call a function when you are done.
| | 05:17 | So cocos2d makes it
really easy to do these things.
| | 05:20 | There are definitely more actions
than I could show in one movie, and I
| | 05:24 | intentionally left many of them out
so you can experiment what cocos2d
| | 05:28 | has available to you.
| | 05:29 | So we are just taking a look at a few
of the actions available in cocos2d.
| | 05:33 | So I encourage you to experiment with
the different actions and see what cocos2d
| | 05:38 | has available to you right out of the box.
| | Collapse this transcript |
| Working with sprite sheets| 00:00 | Designing a game for a mobile device
could take up a lot of memory really fast,
| | 00:05 | so as a game developer, you are
always concerned with memory optimization.
| | 00:10 | SpriteSheets help with memory
optimization, in that they take a bunch of
| | 00:14 | different sprite files and
condense them down into one file.
| | 00:17 | And this almost always saves big on memory.
| | 00:22 | That's because any size that an
image is automatically gets scaled up to
| | 00:26 | the nearest power of 2.
| | 00:28 | For example, 128 is a power of 2.
| | 00:33 | If you have an image that's 100 pixels
by 100 pixels, then regardless of the
| | 00:38 | size of the image, they get scale up
to the nearest power of 2 in memory.
| | 00:43 | So it's treated as if it were 128 by
128 pixels, and that takes up more memory.
| | 00:51 | You can imagine this being a problem if you
have a lot of images that you are loading in.
| | 00:56 | So each time you load an image, you are
wasting 28 pixels of space in both the
| | 01:00 | horizontal and vertical dimensions.
| | 01:02 | So with the SpriteSheet, the idea is
that you don't waste any space because
| | 01:06 | they are all packed into
one power-of-2-safe image.
| | 01:09 | There are two really big
options for creating SpriteSheets.
| | 01:12 | Of course, there are more out there, so
you can research it if you want and pick
| | 01:17 | anyone that you would like.
| | 01:18 | But the two that I have personally
used are Zwoptex and TexturePacker.
| | 01:24 | Let's go to TexturePacker first.
| | 01:27 | TexturePacker is the one that I
use for my current commercial games.
| | 01:31 | The reason is it has a lot of quality
integration with cocos2D that compresses
| | 01:35 | your images down in a format that makes
them take up less space on the device.
| | 01:40 | It also has a few other features that I feel
really give it an edge over the competition.
| | 01:45 | The Zwoptex app is also great because
it has an online Flash version that you
| | 01:50 | can try out for free.
| | 01:52 | Both apps are relatively inexpensive
and will save you a lot of memory and a
| | 01:58 | lot of time when developing your games.
| | 02:01 | So while you don't have to buy one
for this course, I do recommend it.
| | 02:05 | Again, I am not advertising for any one
over the other, and I don't get paid by
| | 02:10 | Zwoptex or TexturePacker
to say anything about them.
| | 02:12 | I have used these products
in my own commercial games.
| | 02:16 | So let's click on the Flash
version at the Zwoptex site.
| | 02:26 | So again, this is a free online tool,
so if you don't feel like buying one of
| | 02:30 | these products right now,
then just use the Flash version.
| | 02:32 | You can go to File > Import Images, and
then I am going to go to my Desktop, in
| | 02:39 | exercise files folder,
| | 02:42 | in Chapter 1. I am going to import
a0001 through a0031, and I'll click Open.
| | 02:52 | These all get opened in this web
app here, and I can choose a range.
| | 02:56 | I can choose any way I want it to arrange.
| | 03:00 | I'll just choose by name
and width. It doesn't matter.
| | 03:03 | So here I have all my sprites organized.
| | 03:06 | Now I can mess with the size of the
canvas if I wanted to, to optimize this, but
| | 03:10 | I am not going to do that right now.
| | 03:12 | And from here, I could save the file
by going to File > Export Texture and
| | 03:18 | File > Export Coordinates.
| | 03:19 | So what you are going to get from the
texture is a PNG file with all of these
| | 03:23 | images in it, and what you get when you
export coordinates is a PLIST file that
| | 03:28 | contains references to all of the images.
| | 03:29 | So you are going to need both to
do what we are going to do next.
| | 03:33 | So just have that ready
and meet me over in Xcode.
| | 03:37 | So here I already have my PLIST
and my PNG file in my project.
| | 03:41 | So let's take a look at
how to use it in cocos2d.
| | 03:45 | Right above where I create the mole
in my init method, we are going to type
| | 03:49 | double brackets and then the
inner brackets, CCSpriteFrameCache,
| | 03:56 | sharedSpriteFrameCache, and then the
outer brackets, addSpriteFramesWithFile.
| | 04:05 | And in the file I am going to pass
in a string for my PLIST file, which is
| | 04:09 | called sprites.plist.
| | 04:13 | You can see that, and I'll pass in the
name to my PLIST file, which is moles.plist.
| | 04:17 | So there you have it.
| | 04:23 | Go back to HelloWorldLayer.m, type in
moles.plist, and now I can reference the
| | 04:32 | sprites by their frame names, which
correspond by default to their file names.
| | 04:38 | So let's say I want to load mole a0011
and I reference that frame when I load it.
| | 04:46 | So go back to HelloWorldLayer.m,
and then I am going to change CCSprite
| | 04:51 | spriteWithFile to CCSprite
spriteWithSpriteFrameName. And I pass in an NS
| | 04:59 | string for the name of the
sprite, which is a0010.png.
| | 05:05 | Now, if you want to make sure that this is
working, you can use any number, 1 through 31 here.
| | 05:10 | So I'll just test the app in the
simulator, and you should see the mole is on
| | 05:15 | the screen as he was before.
| | 05:17 | Now the difference is that this mole is
loaded from a SpriteSheet and not a single file.
| | 05:23 | So to recap, you create your
SpriteSheet with a SpriteSheet creator.
| | 05:28 | Personally, I've used Zwoptex and TexturePacker.
| | 05:32 | You can load the sprite frames in
using a call to the SpriteFrameCache and
| | 05:37 | using its method, add
SpriteFramesWithFile, and there you are going to add the
| | 05:42 | PLIST file. And then you can create a
sprite using your SpriteSheet by the class
| | 05:46 | method spriteWithSpriteFrameName, and
simply pass in the string which will
| | 05:52 | correspond to the file name of your sprite.
| | Collapse this transcript |
| Creating simple frame animations| 00:00 | While properties of a sprite
can be animated using actions,
| | 00:04 | typically character animations are
done using a series of still frames.
| | 00:09 | Let's take a look at how to
apply a frame animation in cocos2d.
| | 00:13 | Right below where we create the mole,
I'm going to create an NSMutableArray.
| | 00:19 | This is going to be called frames,
and I'll allocate an init NSMutableArray here.
| | 00:26 | So the first thing that you are
going to need is an array of frames.
| | 00:32 | Then we will create a for loop.
| | 00:34 | We will start with an integer called i,
set it equal to one, as long as i < 10,
| | 00:40 | and i++. And here the first thing I am
going to do is create an NSString, and I'm
| | 00:47 | going to get the frame name.
So we will call this frameName.
| | 00:51 | So here I will create an NSString
called frameName and set it equal to, in
| | 00:56 | brackets, NSString
stringWithFormat, and I will create an NSString.
| | 01:06 | I will type "a%04i.png" and after the
close quote, a comma and then an i. So as
| | 01:12 | the loop goes on, it will add frame
a0001.png and so forth, up to frame 10.
| | 01:21 | I want to make sure that i is not just
less than 10, but i is less than or equal
| | 01:26 | to 10. So we want to include that tenth frame.
| | 01:29 | So on the next line, I am going to type
some brackets and then frames, addobject,
| | 01:35 | and the object is going to be, double brackets,
CCSpriteFrameCache sharedSpriteFrameCache
| | 01:43 | SpriteFrameByName, and the
name is going to be FrameName.
| | 01:49 | And then below the loop, we
will create a CCAnimation object.
| | 01:57 | A CCAnimation is a set of frames.
| | 01:59 | So we will call this a. I'll set it equal to, in brackets,
CCAnimation animationWithFrames and delay.
| | 02:08 | The frames are going to be frames.
| | 02:10 | We already created in that NSArray,
and the delay is going to be 1.0f/24.0f.
| | 02:16 | When I created this animation in Flash, I
set 24 frames per second as the frame rate.
| | 02:22 | So just remember the frame rate that you
used before, and you can pass it in here.
| | 02:26 | On the next line, type some brackets
and then type mole runAction, and the
| | 02:32 | action is going to be CCAnimate--
different from a CCAnimation.
| | 02:37 | Remember, animation is a set of frames, and
CCAnimate is an action that runs CCAnimation.
| | 02:43 | So actionWithAnimation and pick the
one that says restoreOriginalFrame.
| | 02:49 | So the animation's going to be a, and
restoreOriginalFrame is going to be NO.
| | 02:54 | So after the animation plays,
it will stay at that last frame.
| | 02:58 | So let's test this out in the simulator.
| | 03:07 | So you notice the mole starts out up
and then it goes down and the animation
| | 03:11 | plays, so if you wanted him to start
out down, you can change that first frame,
| | 03:16 | which displays when we create the mole, as a0001.
| | 03:18 | So let's test that again.
| | 03:22 | So there's the mole popping up.
| | 03:30 | Now, let's say you wanted the
mole to go down when you hit him.
| | 03:34 | Just copy all the code
that handles the animation,
| | 03:37 | so from mole runAction all the way up
to NSMutableArray frames. Copy that and
| | 03:43 | then paste it in ccTouchesBegan in the
if statement, where you check to see if
| | 03:47 | the touch collided with the mole.
| | 03:49 | So paste that in. And then the loop is
going to be a little bit different this time;
| | 03:54 | i is going to run from 11 through 20.
| | 03:58 | So just change that, i =11 as
long as i<= 20, and that's it.
| | 04:05 | So when you hit the mole, it should go down.
| | 04:12 | So on the simulator, you'll see the mole
animate up, and then you tap the mole and
| | 04:16 | it will animate down.
| | 04:24 | So to create a frame animation, create
an NSArray of frames and add to it by
| | 04:30 | iterating through a loop, create a
CCAnimation to hold the frames, and then use
| | 04:37 | the CCAnimate action to run the animation.
| | Collapse this transcript |
| Setting a game to display in Portrait mode| 00:00 | Not all iOS games are
going to be in landscape mode.
| | 00:04 | If you come up with a great idea that
better suits portrait mode, it's good to
| | 00:08 | know how to do that with cocos2d.
| | 00:10 | The first place to go is in
GameConfig.h. In here when you see
| | 00:16 | GAME_AUTOROTATION defined, change
kGameAutorotationUIViewController to
| | 00:24 | kGameAutorotationNone and save the file.
| | 00:30 | Now I'll go over to AppDelegate.m.
Scroll down, toward the middle of the
| | 00:38 | applicationDidFinishLaunching method,
| | 00:41 | and in here you can just copy and
paste that line of code that sets the
| | 00:44 | director's device orientation.
| | 00:46 | So copy that, paste it after that
endif line of code, and then test in the
| | 00:53 | simulator, and you should see now
that the game launches in portrait mode.
| | 00:58 | And there is the Hello
World text in portrait mode.
| | 01:01 | So remember, to adjust auto-rotation,
change your settings in GameConfig.h and
| | 01:09 | then update AppDelegate so that the
director's device orientation is portrait.
| | Collapse this transcript |
|
|
2. Viewing the Core ClassesViewing constants and the AppDelegate class| 00:00 | For this game I already
have a lot of prewritten code.
| | 00:04 | Everything is already done,
except for the gameplay itself.
| | 00:08 | That way you can specifically focus
on learning cocos2D to make games.
| | 00:14 | Now both for the sake of those of you
who don't have the exercise files and for
| | 00:18 | the sake of those of you who do, I am
going to walk you through all the code
| | 00:23 | that's already been written.
| | 00:24 | So first I'm going to go to Constants.h.
In Constants.h I have several different
| | 00:30 | values defined, so you'll see MOLE
TYPE C, B, and A. Those are just simple
| | 00:35 | strings, and they correspond to
the different MOLE frame types.
| | 00:39 | So the green moles are MOLE_TYPE_A.
The frames are named A 0001 through A 0030.
| | 00:50 | MOLE_TYPE_A, for example,
refers to the green MOLE.
| | 00:53 | I'm going to use these later in the
code so I can easily refer to the
| | 00:58 | different types of MOLES.
| | 00:59 | So the frame for MOLE A would be
A 0001.png, for example, and the frame for a
| | 01:07 | blue MOLE, which is MOLE_TYPE_B,
would be B 0001.png, for example.
| | 01:14 | Then we have a value to store a user
default, which is the amount of times the
| | 01:19 | person has played the game, have a key
to access the high score, and the key
| | 01:27 | that tell us whether the user rated the game.
| | 01:29 | And we have different values for the skins--
| | 01:33 | there's moles, and there's jetpack--and
these are named like this intentionally.
| | 01:37 | These are what I named the s
SpriteSheet, so there's moles.plist and then
| | 01:42 | jetpack.plist. And then I have some
enumerated values so I can access the
| | 01:47 | moles using numbers.
| | 01:49 | That makes it easier to go through a
switch case statement and see what type of
| | 01:52 | mole I am working with.
| | 01:53 | Let's go over to AppDelegate.h.
In this header file, you'll see it's
| | 01:59 | pretty straightforward.
| | 02:00 | I only added a few different values
here. We have Boolean, hasPlayedbefore,
| | 02:06 | Whacked3 and Whacked4, a string for
the current skin and a whole bunch of
| | 02:11 | integers for timesPlayed, currentAction,
greenMolesWhacked, blueMolesWhacked,
| | 02:20 | yellowMolesWhacked. And some methods defined.
| | 02:25 | FinishedWithScore, which is going to
run when we finish playing the game,
| | 02:31 | getHighScore, pause, resume,
isGameScene, getCurrentSkin, setCurrentSkin, and
| | 02:38 | getViewController. So pretty straightforward.
| | 02:41 | Let's go to AppDelegate.m and
see anything that's different here.
| | 02:46 | I've imported Constants,
SimpleAudioEngine, Mainmenu, Main Game class.
| | 02:56 | Initialize timesPlayed
using the UserDefaults key.
| | 03:00 | Set the current skin to be the MOLE skin.
All this is set up in the cocos2D template.
| | 03:08 | I commented out the line of code that
shows DisplayFPS. That shows the frames per
| | 03:13 | second on the screen. And in the
runWithScene call, I'm calling Mainmenu node.
| | 03:22 | So main menu is not a CCLayer subclass;
| | 03:25 | it's a CCScene subclass. I'm grabbing an auto
release instance with the node class method.
| | 03:33 | Here in application we'll resign active.
| | 03:36 | I'll check to see if it's the
GameScene, and if so, send a message to the
| | 03:41 | GameScene to pause the game.
| | 03:44 | If not, I simply pause the director.
And in applicationDidBecomeActive,
| | 03:50 | if it's not the GameScene, I resume the
director. This is because the GameScene
| | 03:55 | handles its own pausing and resuming.
| | 04:01 | Scroll down. finishWithScore is empty,
getHighScore returns the UserDefault's
| | 04:06 | value for the high score key. Pause
and resume check to see if it's not the
| | 04:13 | GameScene and if not, then pause and
resume the director respectively. The
| | 04:18 | isGameScene method checks to see if
the class of the running scene is the
| | 04:24 | GameClass and returns yes or no. Then we
have simple getters and setters for get-
| | 04:29 | and setCurrentSkin, simple getter for
getViewController, and AlertView delegate
| | 04:35 | handler, and that's it.
| | 04:37 | So again, if you don't have access to
the exercise files, you can just copy down
| | 04:40 | my code here and follow along.
| | Collapse this transcript |
| Exploring the Game and Mole classes| 00:00 | The main class we're going to be
working in to develop this game is the
| | 00:04 | GameClass; that class
controls all of the gameplay.
| | 00:08 | In Game.h, you'll see that I have game
as a subclass of CCScene, and I've adopted
| | 00:14 | the CCStandardTouchDelegate protocol.
| | 00:17 | If you don't have CCLayer as your main
class then you don't have that easy to
| | 00:21 | add touch functionality, where you just
have the one line of code, and type self
| | 00:25 | dot is touch enabled to handle touches.
| | 00:28 | So if you are subclassing the scene, you
have to manually set up your scene as a
| | 00:32 | delegate to handle touches. So then I
have two CCArrays. I have some float
| | 00:38 | values. I have a CCLabelBMFont.
| | 00:41 | We'll talk about that class in detail
later on. Some integers, CGSize s to
| | 00:47 | handle the size of the screen,
a reference to the AppDelegate object,
| | 00:51 | CCmenuItemSprite, a few strings, a few
Boolean values, and some methods here.
| | 01:00 | Now I'll move to Game.m. So here I'm
importing classes that you'll see over and
| | 01:05 | over again, like Constants.h,
Mainmenu.h, SimpleAudioEngine.h. Here I'm
| | 01:11 | importing the main classes we will
be working with in the GameClass.
| | 01:16 | The init method doesn't create any objects;
| | 01:18 | it just initializes primitives.
| | 01:22 | InitializeGame runs a method
called startGame, and startGame starts a
| | 01:28 | selector called tick.
| | 01:30 | What the schedule method does is it
runs a selector at a certain time interval,
| | 01:35 | and by default that's along with the
frame rate of your app. So there is a
| | 01:39 | method called
chooseWhichMoleToMake, which is empty.
| | 01:41 | The tick method adds on to timeElapsed
in the amount of DT, which is the time
| | 01:48 | between iterations of the selector
running. So it's going to be 160th of a
| | 01:53 | second each time. And if the timeElapsed
is greater than the time allowed between
| | 01:57 | moles, then we run
chooseWhichMoleToMake and set timeElapsed to 0.
| | 02:04 | showMole is empty. getDownMoles returns
an array of all the moles that are down.
| | 02:11 | We'll look at the more class in
detail in just a minute in this movie.
| | 02:14 | getUpMoles returns an
array of moles that are up.
| | 02:17 | CCTouchesBegan is empty, as is didScore,
missedMole, gameOver, pauseGame, and
| | 02:26 | resumeGame. We have getMoles up,
which returns the number of upMoles; and
| | 02:33 | mainmenu, which returns us to the Mainmenu;
| | 02:36 | playAgain, which replaces the current
running instance of games scene with a new
| | 02:42 | instance of the game scene;
| | 02:44 | onEnterTransitionDidFinish, which is an
event handler that runs once everything
| | 02:49 | is loaded for the scene to start, and
that when we run an initializeGame, which
| | 02:53 | starts all of the magic.
| | 02:55 | onExit runs when scene is exiting, the
last thing before its de-allocated, and in
| | 03:02 | dealloc I just have a call to dealloc
and showing self just to make sure that I
| | 03:07 | can see in the output window
when scenes are getting released.
| | 03:10 | I highly recommend this when you're
starting out with cocos2D because a lot of
| | 03:14 | times you'll find that you'll forget to
release an object and your scenes won't
| | 03:18 | be getting released. So each time you
change to a new scene, you're adding to
| | 03:22 | the memory that your application is consuming.
| | 03:24 | So just keep that in mind. This is
a really good way to keep track of
| | 03:28 | your memory management.
| | 03:29 | Let's go to Mole.h. So we have
some Booleans, some floats, an NSString,
| | 03:36 | a reference to AppDelegate, and some
methods here. And let's go over to Mole.m and
| | 03:43 | look at them in detail.
| | 03:44 | Again, note which classes are imported,
and in the init method set some basic values.
| | 03:50 | I'm not creating sprites here. And the
reason why I do that is because sometimes
| | 03:56 | the init method tries to create
objects when they're not accessible, and so I
| | 04:01 | always create objects after
onEnterTransitionDidFinish.
| | 04:07 | So startWithType actually creates a mole.
So I'll run stopAllActions, which is
| | 04:14 | a built-in cocos2D method that stops
all actions that are currently running,
| | 04:18 | sets isUp to YES, sets the amount of time
the instance is going to be up based
| | 04:24 | on the type of mole.
| | 04:26 | Then it sets didMiss to YES, sets the
type property to the type passed in, and
| | 04:32 | then the scaleX is randomized.
| | 04:34 | Of course that's just an optional
feature, but I feel like it makes the game
| | 04:38 | look a little bit
different while you playing it.
| | 04:39 | It kind of mixes things up.
| | 04:42 | So reset sets isUp to NO, and if the
person missed the mole then we run the
| | 04:51 | missedMole method on the parent. And
in stopEarly we make the mole go down
| | 04:58 | without making the parent miss.
| | 05:01 | So we set didMiss to NO,
stopAllActions, and we run self stop, which will make
| | 05:06 | the mole go down, and we'll do that later on.
| | 05:08 | getIsUp returns if the mole is
up. wasTapped is empty now. and
| | 05:14 | getAnimationWithFrames and
reverseAnimationWithFrames return CCAnimations of sets of frames.
| | 05:20 | These are basically helper methods
that I created so I can quickly create
| | 05:24 | animation frames without having to
write a for loop every single time.
| | 05:29 | getType returns the type, and that's it.
| | 05:31 | So as we go throughout the rest of this
course, we're going to be adding a lot
| | 05:35 | to the mole and game classes because
these classes control all of the gameplay
| | 05:40 | and logic for the game we're creating.
| | Collapse this transcript |
| Understanding the custom pop-up menu utility | 00:00 | All of the pop-up menus in the
game used the PopUp class;
| | 00:04 | let's take a look at the PopUp class
and PopUp.h. It's a subclass of
| | 00:09 | CCSprite. It has two CCSprites
and a CCNode called Container.
| | 00:14 | A CCNode can be a CCScene, Layer, or Sprite.
| | 00:20 | So I chose CCNode here because I don't
want to have to worry about what data
| | 00:25 | type is used for the container. And I
have a class method called popUpWithTitle,
| | 00:30 | and then I have some instance methods.
| | 00:33 | So let's go to our PopUp.m.
| | 00:37 | Here I'm importing CCSprite+
DisableTouch, which is an extension that I
| | 00:42 | wrote, which we'll look at in just
a minute, and then CCmenuPopup.h.
| | 00:48 | ANIM_SPEED is defined as .2f.
| | 00:50 | I have a tag for the background
called tBG, set to equal to 1, and when that
| | 00:58 | class method popUpWithTitle runs, it
returns an autoreleased instance using the
| | 01:03 | initWithTitle method.
| | 01:05 | initWithTitle is pretty
straightforward for the most part.
| | 01:08 | It creates a window and then a
background, and the background is just an empty
| | 01:14 | sprite that I created as a rectangle
that covers the whole screen, using the
| | 01:19 | setTextureRect method. And since I'm
using the CCSprite extension I created, I
| | 01:25 | run a method called disableTouch. And as
we'll look at in just in a minute, that
| | 01:29 | disables all touches for anything underneath it.
| | 01:33 | Set the position of the window and
the scale, create a text label, set its
| | 01:40 | opacity and position, create a
description label, set its opacity and position.
| | 01:46 | And I add them as children of the
window, add the background as a child of self,
| | 01:54 | and the window is a child of self.
| | 01:56 | Then I use an action to fade the
background and to animate the pop-up menu to
| | 02:03 | scale up and scale back to normal size.
| | 02:05 | The closePopUp menu displays a really
quick animation that re-enables touch on
| | 02:12 | the background and all other elements behind it.
| | 02:15 | Then the window animates out and runs
allDone, which runs the built-in method
| | 02:20 | remove FromParentAndCleanup, which
removes a child from its parent, taking it
| | 02:25 | out of the display list of objects
so it can be released from memory, and
| | 02:30 | cleanup, which specifies whether you
want it to get rid of all of its children.
| | 02:37 | So let's go over to CCSprite+
DisableTouch.h. It's using the DisableTouch
| | 02:44 | extension, implements a
CCTargetedTouchDelegate protocol, and has
| | 02:50 | two instance methods.
| | 02:51 | Let's go to the .m file.
And ccTouchBegan returns Yes.
| | 02:57 | What that does is it captures all of
the touches and doesn't let anything
| | 03:03 | behind it receive touches.
| | 03:06 | So I do that in the
disable- and enableTouch methods.
| | 03:09 | So you see disableTouch adds this
object as a delegate of the touch dispatcher,
| | 03:16 | with the priority of -1000.
| | 03:19 | Now negative priority actually gets a
higher priority. So all those Touches
| | 03:24 | refers to whether or not
objects below it can be touched.
| | 03:27 | So I put YES there, and then
enableTouch removes it as a delegate, so touches
| | 03:33 | get enabled below this object.
| | 03:35 | Remember, this is for the background
when the pop-up menu shows up, which is a
| | 03:39 | semi-transparent black area
that covers the whole screen.
| | 03:42 | Another class used along with
the pop-up is the CCmenuPopUp.
| | 03:46 | Let's go to CCmenu.h.
CCmenuPopUp is an extension of CCmenu.
| | 03:52 | A CCmenu is a collection of menu
buttons. So you can use them for a pause
| | 03:57 | button, for example, in your game.
| | 03:59 | Something that's just going to capture
user interactivity. Not so much like an
| | 04:03 | animated object like a sprite,
but more for interface elements.
| | 04:08 | And so what you would do is create an
array of CCmenu items and then you pass
| | 04:13 | them into the CCmenu constructor
and you create a list of buttons.
| | 04:17 | We'll look at that in more detail later on.
| | 04:20 | Let's go to CCmenuPopup.m, and then
I have registerWithTouchDispatcher.
| | 04:26 | I am overriding this method.
| | 04:28 | I'm setting the priority to -1001.
So any buttons placed in the pop-up menu will
| | 04:35 | still work, and they won't be disabled,
because of the priority of the background,
| | 04:39 | which disables everything behind it.
| | 04:41 | So in order for them to be registered,
they need to have a lower priority.
| | 04:46 | So in ccTouchBegan, the first thing
that I do is check to see if there is an
| | 04:50 | item that was touched. So if some
button was touched then we're going to go on
| | 04:55 | with a method, and if not,
then we're going to return NO.
| | 04:58 | That's going to stop handling the touch.
| | 05:00 | So I then have an array of the ancestors,
so there's the object's parent and then
| | 05:06 | the parent's parent, and
then the great grandparent.
| | 05:08 | So then I'll loop through
all the objects and ancestors.
| | 05:12 | I check to see if it's a pop-up,
and if so, close the pop-up.
| | 05:17 | So whenever a button was touched
that's in the pop-up menu, the pop-up will
| | 05:21 | automatically close. And then finally,
I'm returning whatever is returned in
| | 05:25 | supers version of this method.
| | 05:26 | So using the pop-up menu, you can
easily add interactivity in a pop-up
| | 05:32 | window without having to worry that
buttons behind the pop-up window are
| | 05:36 | going to be touched.
| | Collapse this transcript |
| Examining the code in the MainMenu class| 00:00 | Finally, we'll examine the MainMenu class;
| | 00:03 | in MainMenu.h you'll see that
everything is pretty straightforward.
| | 00:06 | I just have a reference of the
delicate and then a playGame method.
| | 00:09 | In MainMenu.m, I'm importing some of
the classes that you've already seen. And
| | 00:14 | everything here is in the init method.
| | 00:16 | So I create a size object to hold the
size of the screen, tell the audio engine
| | 00:22 | to stop playing background music, set
the delegate, have a string for fileName
| | 00:27 | based on the CurrentSkin.
| | 00:30 | Add the SpriteFrames to the cache
using that file name. I have a font size, set
| | 00:36 | the High Score on the screen based on the
font size. Put the high score at the top-right.
| | 00:43 | Add it as a child of the MainMenu, set
FontName for CCmenuItemFont to the font
| | 00:48 | that I had in my project,
which is called TOONISH.
| | 00:50 | Set the font size of CCmenuItemFont.
And then here we have a CCmenuItemSprite, so
| | 00:58 | this is going to be a button. And it's
called playbutton. And I'm using the class
| | 01:04 | method itemFromNormalSprite,
selectedSprite target and selector.
| | 01:08 | So remember, a CCmenu item is something
that you put into a CCmenu that runs a
| | 01:14 | selector when you click it.
| | 01:15 | So the Sprite returned comes from the
Gamebutton class, which is a custom class
| | 01:21 | which we'll look at in just a minute.
| | 01:23 | Basically the class creates a button
with text, and you could specify whether
| | 01:28 | it's a big button or a small
button using the isBig parameter.
| | 01:32 | I set selectedSprite to Null, since I
don't want the sprite to change when I tap it.
| | 01:37 | The target is self and the selector is
playGame, which just starts the basic game-
| | 01:42 | play. So then you'll see the
leaderboard's button that has the Text Game Center.
| | 01:47 | It runs a method called showLeaderboard.
selectSkinbutton runs selectSkin, the
| | 01:53 | otherGames button runs otherGames, and
the CCmenu is created using those items.
| | 01:58 | And I tell the menu to
alignItems HorizontallyWithPadding.
| | 02:03 | Position the menu, add the
menu as a child of the MainMenu.
| | 02:08 | That's this class. And then I created
another menu just for the play button.
| | 02:12 | So you see that there. And then for
the background, I changed fileName to
| | 02:19 | title.png, and then we'll have
it display as the background.
| | 02:23 | You'll also notice
CCTexture2D setDefaultAlphaPixelFormat.
| | 02:29 | This enables you to change the
quality of your images to improve memory.
| | 02:33 | So RGB565 has no alpha channel and gives
you an optimized quality for the memory used.
| | 02:41 | So this is really good for backgrounds,
but since it doesn't have an alpha
| | 02:45 | channel, it's not too great for sprites.
| | 02:48 | So after I create the background, then
I set the CCTexture2D back to RGBA4444.
| | 02:55 | This is 16-bit color with an alpha channel.
| | 02:58 | Let's go over to Gamebutton.h. So
there are two methods: buttonWithText and
| | 03:03 | buttonText isBig. There are two class
methods here and one instance method. If
| | 03:08 | you go over to Gamebutton.m,
you'll see how it all works.
| | 03:12 | Most of the class methods
return auto-released objects.
| | 03:16 | I just did this to follow the standards
of cocos2d. And then the init with text
| | 03:20 | method is where the label is created,
the buttons DisplayFrame is set, based on
| | 03:27 | whether or not the button isBig. Keep
in mind that you can change a sprite's display
| | 03:31 | frame at any time using the
setDisplayFrame method. Then a label is
| | 03:35 | created with the appropriate text.
| | 03:37 | I created an extra label
that's a shadow, so it's just black--
| | 03:41 | it's the same text--and I offset it a
little bit, and I added it as a child
| | 03:46 | below the main label.
| | 03:47 | So that's all of the code, and it
has been custom written for this game.
| | 03:50 | Once you have everything set up and
you have an understanding of the basic
| | 03:55 | foundation of the game, you're ready
to start writing the actual gameplay.
| | Collapse this transcript |
|
|
3. Building a Basic Mole-Whacking GameAdding the background and HUD elements| 00:01 | Before we start writing the code for
the game, let's take a look at what we
| | 00:03 | have in the simulator.
| | 00:05 | So I'm going to test the app,
and right now we basically have the main menu.
| | 00:14 | We see the main menu here. It says High Score:
| | 00:16 | 0, and if you click SKINS, you'll see the skins,
but they won't do anything if you click them.
| | 00:25 | GAME CENTER doesn't do anything.
| | 00:27 | MORE GAMES will try to launch the
App Store which isn't installed in the
| | 00:30 | simulator, so you'll have to test it on
a device to see that working. And if you
| | 00:34 | click the Play button, you
simply get a blank screen.
| | 00:37 | So let's close the simulator and go
over to Game.m, and we'll start writing
| | 00:43 | the code to add the background, the
carrots out at the top-right of the
| | 00:47 | screen, and the Pause button.
| | 00:50 | So in the initializeGame method, this is where
we're going to create all of our art elements.
| | 00:56 | First, I'll set the delegate.
| | 00:59 | Set it equal to AppDelegate in
parentheses and an asterisk, a set of double brackets,
| | 01:09 | UIApplication sharedApplication
and in the outer brackets, delegate.
| | 01:16 | Go to the next line, and make sure
the director is playing, so we'll call
| | 01:22 | CCDirector in double brackets,
sharedDirector, and in the outer brackets resume.
| | 01:31 | And on the next line we'll set s equal to, two
sets of brackets, inner brackets CCDirector
| | 01:40 | sharedDirector, outer brackets, winSize.
| | 01:44 | Create an NSString called fileName.
| | 01:49 | This is going to represent the sprite
sheet PLIST file name, and we're going to
| | 01:52 | grab this based on the name of the current skin.
| | 01:56 | So in brackets, NSString
stringWithFormat is going to be %@ symbol.plist,
| | 02:06 | after the quotes a comma, and then brackets,
and in the brackets, delegate getCurrentSkin.
| | 02:15 | So this will be moles.plist
or jetpack.plist, for example.
| | 02:18 | Go down a few lines, and then we'll add
this sprite frames using that PLIST file.
| | 02:24 | So double brackets
CCSpriteFrameCache sharedSpriteFrameCache
| | 02:31 | addSpriteFramesWithFile, and
the file is going to be fileName.
| | 02:37 | Now we'll initialize the carrots array.
| | 02:40 | So carrots = and double brackets, and
we'll just have CCArray alloc and then init
| | 02:55 | in the outer brackets.
| | 02:56 | Now just think of a CCArray just like
an NSMutableArray; the main difference is
| | 03:01 | that you can easily grab a random
object out of a CCArray, which is going to be
| | 03:05 | useful for us later on.
| | 03:06 | Now since we init an object there,
we're going to have to release it,
| | 03:09 | so I want you to scroll down in your
code and then find the onExit method. In
| | 03:15 | there we'll release the carrots.
| | 03:16 | So carrots release.
| | 03:20 | Scroll back up to initializeGame, and the
next step is to load in the background.
| | 03:26 | So remember, for optimization, we want to
change the default alpha pixel format to
| | 03:32 | not support alpha, so we don't waste any memory.
| | 03:35 | So in brackets, CCTexture2D,
setDefaultAlphaPixelFormat, and that's going to be
| | 03:41 | kCCTexture2DPixelFormat_RGB565.
| | 03:42 | So now we'll create and load in the
background and then change the pixel format back.
| | 03:53 | So CCSprite, we'll call this *bg, and we'll set it equal
to, in brackets, CCSprite spriteWithFile
| | 04:09 | and we're going to get the file
from the delegate's current skin again.
| | 04:14 | So brackets, NSString. We'll type
stringWithFormat, and in there it's going to be
| | 04:23 | %@ symbol _bg.png. After the close quote,
a comma, and a space, some more brackets.
| | 04:31 | In the brackets, delegate getCurrentSkin.
| | 04:36 | So this will be moles_bg.png or jetpack_bg.png
based on the current skin of the game.
| | 04:44 | So let's set the
background's anchorPoint to 0, 0,
| | 04:47 | so that's ccp. Remember, this is a
percentage so that's bottom-left anchor point.
| | 04:55 | So we don't have to set it's position,
because it's going to be a aligned with
| | 04:58 | the bottom-left of the screen,
and it takes up the whole screen.
| | 05:01 | And then in brackets we'll call self
addChild. We'll add bg, and it's z will be -1.
| | 05:07 | Next I'll copy and paste that
line of code where we change the
| | 05:13 | DefaultAlphaPixelFormat and paste that
right underneath self addChild bg, and
| | 05:20 | change the AlphaPixelFormat to RGBA4444.
| | 05:25 | Again, this is for memory optimization, and
it will give better performance in our game.
| | 05:30 | Now we'll create a loop to
display the carrots on the screen.
| | 05:34 | So type for. This will be int, i, we'll
set it = 0 and as long as i < carrotsLeft,
| | 05:44 | i++, and we'll create the carrots from
the top-right corner of the screen.
| | 05:52 | So in here CCSprite. We'll call this c,
and we'll set it equal to, in brackets,
| | 06:02 | CCSprite spriteWithSpriteFrameName.
That's going to be life.png as an NSString.
| | 06:19 | We'll set it's anchorPoint to be the
top-right, so c.anchorPoint = ccp(1, 1).
| | 06:29 | I like to set anchor point so that
I don't have to do as much calculation
| | 06:32 | when I'm setting the position of
objects, so if that's why you're wondering why I
| | 06:36 | keep modifying the anchor points,
| | 06:37 | I like to put something
that's at the bottom-left at 0, 0;
| | 06:40 | if it's at the top-right, I put it at 1, 1;
| | 06:42 | if it's at the top-left I put it at 0, 1.
| | 06:46 | So next, we'll set the position so
c.position, and we'll set it equal to ccp. And
| | 06:52 | in parentheses the X value is going to
be s.width - i *, so an asterisk, and we
| | 07:04 | want to do the width of the carrot.
| | 07:07 | We can get that through
its contentSize property.
| | 07:11 | So c.contentSize--make sure you
don't have the underscore--.width--that will give us
| | 07:18 | the width of the carrot. And then we'll
set the Y position of the carrot at s.height.
| | 07:26 | So that will align the carrots with the
right edge of the stage, and each one will
| | 07:31 | shift in the amount of the
carrots' width to the left.
| | 07:35 | So we'll draw three carrots,
starting at the top right corner.
| | 07:37 | So now we'll add this to the carrots array.
| | 07:40 | So carrots addObject c. And then
on the next line, self addChild:
| | 07:54 | c, so we'll add that
carrot, and the z will be 10.
| | 07:59 | Finally, we'll add the
Pause button to the screen.
| | 08:04 | So a few lines below the for loop,
set pausebutton equal to, and in brackets, type
| | 08:12 | CCmenuItemSprite and then start to
type item. And then what I want you to pick is
| | 08:20 | itemFromNormalSprite,
selectedSprite, target selector.
| | 08:24 | So the NormalSprite is
going to be in brackets, CCSprite
| | 08:29 | spriteWithSpriteFrameName, and the
frame name is going to be pause_button.png.
| | 08:38 | selectedSprite is going to be NULL,
target is going to be self, and for selector,
| | 08:44 | I'll type at symbol selector, and in the
parentheses I'm going to type pauseGame.
| | 08:52 | On the next line, I'm going to create a
CCmenu and put a pausebutton in the menu.
| | 08:56 | So CCmenu, we'll just call this
menu, and we'll set it equal to CCmenu
| | 09:05 | menuWithItems. We'll pass in the
pausebutton and then nil after the comma.
| | 09:12 | We'll set the position of the Pause button.
| | 09:13 | So pausebutton.position = ccp and
in the parentheses type s.width/2 -
| | 09:27 | pausebutton.contentSize.width/2.
| | 09:32 | This will put it at the bottom-right, because a
menu by default is at the center of the screen,
| | 09:38 | so we're basing it off those coordinates.
| | 09:41 | So then a comma and then in parentheses
-s.height/2, after the parentheses +
| | 09:53 | pausebutton.contentSize.height/2.
| | 09:59 | Finally, we'll add the Pause menu to the
screen by typing "self addChild:menu," and
| | 10:07 | we'll give it a z position of 100.
| | 10:12 | Now that we have created the
background and the carrots and the Pause button,
| | 10:16 | let's test the app in simulator.
| | 10:17 | So you should click Play. You see the
background, the carrots, and the Pause button.
| | 10:31 | So if anything is missing, or you have
an error, just go through your code and
| | 10:34 | make sure that it matches mine perfectly.
| | 10:37 | So now the background and heads-
up display elements are all set up.
| | Collapse this transcript |
| Laying out moles in the Main Game class| 00:00 | Now that the background elements of
our game are set up, let's take a look at
| | 00:04 | laying out the moles on the screen.
| | 00:07 | The first thing we'll do is, in the
initialize game method, right under where we
| | 00:11 | allocate and init the carrots array,
| | 00:14 | we'll do the same thing for the moles array.
| | 00:18 | So CCArray alloc init, and then we'll
scroll down to onExit at the bottom of our
| | 00:25 | code and release the moles.
| | 00:30 | We'll scroll back up to initialize game.
So right after where we create the moles array,
| | 00:36 | we're going to create some variables that
we'll use for padding when we create the moles.
| | 00:40 | So create two float variables, the
first one called hPad, short for horizontal
| | 00:46 | padding, and we'll set that equal to 20.
And the next one we'll call vPad, and
| | 00:52 | we'll set that equal to 25.
| | 00:55 | Create a for loop, use a integer
called i = 1, and as long as i <= 4--this
| | 01:09 | represents rows--then i++.
| | 01:12 | Now we'll create a loop inside
of that loop for the columns.
| | 01:16 | So for int. We'll call this j, set
it equal to 1 as long as j <= 6, then j++.
| | 01:28 | So we have a loop running within a loop:
that outer one for the rows, the inner
| | 01:36 | ones for the columns.
| | 01:38 | So inside of the inner loop, we'll
create a Mole by tying Mole, and we'll call it
| | 01:42 | mole, all lowercase. And we'll
set it equal to, in brackets, Mole
| | 01:51 | spriteWithSpriteFrameName, and
we'll pass in the NS string a0001.png.
| | 02:01 | Next, we'll set the moles position.
| | 02:02 | To do that, we'll use a horizontal
and vertical padding and our iterators.
| | 02:07 | So mole.position = ccp, and in the
parentheses, we'll first type the X value,
| | 02:16 | which is going to be j *
mole.contentSize.width+hPad, and then i *
| | 02:31 | mole.contentSize.height + vPad.
| | 02:41 | Next, we'll add this mole into the moles array.
| | 02:44 | So Moles, addObject, mole, and finally
we'll add this moles to the screen by
| | 02:51 | calling self addChild mole and
give it a z position of 1.
| | 02:58 | So if we test the app now, in the
simulator we should see all of the moles
| | 03:03 | laid out on the screen.
| | 03:11 | So I'll click Play from the main
menu, and there are all the mole holes.
| | 03:17 | So we successfully laid out all
the moles using two for loops.
| | 03:21 | So if you ever need to lay out
objects in a grid, create some padding
| | 03:26 | variables, and you can use two for
loops, one within the other, to lay out the
| | 03:32 | objects in a grid pattern.
| | Collapse this transcript |
| Animating the moles| 00:00 | Now we'll make the moles animate up
and down to give them some more life.
| | 00:04 | Scroll down into the tick method in Game.m.
Note that chooseWhichMoleToMake runs each time
| | 00:12 | it's time to make a mole.
| | 00:14 | So let's define what chooseWhichMoleToMake does.
| | 00:17 | The first thing we'll do
is set the nextMoleType.
| | 00:19 | So type nextMoleType
equals MOLE, in all caps, _TYPE_A.
| | 00:24 | And then we'll run a method
called showMole, so self showMole.
| | 00:31 | Now we'll define what showMole does.
| | 00:34 | showMole is going to grab a random
mole and then present it on the screen.
| | 00:39 | Here we'll create a variable
called mole, all lowercase.
| | 00:44 | It's of the datatype mole,
capital M, and we'll set it equal to double
| | 00:48 | brackets and inner brackets, CCArray, and
then a space, arrayWithNSArray, and then
| | 01:03 | pass in, in brackets, self getDownMoles.
| | 01:09 | So we're grabbing a random mole that's down.
| | 01:14 | So in the outmost brackets, type
randomObject, and then on the next line
| | 01:22 | type some brackets, and in the brackets, type
mole startWithType and pass in nextMoleType.
| | 01:29 | Now let's jump over to Mole.m, and
we'll define that animation in startWithType.
| | 01:37 | At the very bottom of that method,
create a few new lines of code and then in
| | 01:41 | brackets, type self runAction, and
the action is going to be, in brackets,
| | 01:49 | CCAnimate actionWithAnimation and
then a colon, and in brackets, self
| | 02:00 | getAnimationWithFrames. The first
parameter will be 1 and then to :10.
| | 02:08 | After the close bracket,
type restoreOriginalFrame:NO.
| | 02:17 | So we'll have the mole animate up,
and let's save and test the app.
| | 02:21 | So I'll click Play, and the moles
should be animating up. There they are.
| | 02:37 | So now we want to do is make them
animate down after instanceUpTime has passed.
| | 02:47 | So on the next line of code type
some brackets and type self runAction:
| | 02:55 | and brackets, CCSequence actions:
| | 03:01 | I'm going to type some brackets, comma
nil, and then create a new line for the
| | 03:10 | brackets and the comma.
| | 03:11 | I'll type a CCDelayTime actionWithDuration.
| | 03:20 | The Duration is going to be the
instanceUpTime, and then on the next line some
| | 03:26 | brackets and a comma,
CCCallFunc actionWithTarget:
| | 03:36 | self, and then selector will be @
selector and in parentheses, stop.
| | 03:43 | Now let's scroll down and define what stop does.
| | 03:48 | In stop, we're going to play the
opening animation backwards, so the mole goes
| | 03:53 | back in his hole, and then reset it to mole.
| | 03:57 | So I'm going to do a scroll back up.
| | 03:59 | I'm going to copy those two lines of
code where we run the action on self.
| | 04:03 | I'm going to recycle them for stop.
| | 04:06 | So I'll paste them into the stop
method, and I'm going to change the CCCallFunc
| | 04:12 | selector to reset. And then I'm just
going to cut and paste that CCAnimate
| | 04:18 | action right over the CCDelayTime.
| | 04:26 | And instead of
getAnimationwithFrames, it's going to be
| | 04:29 | reverseAnimationwithFrames.
| | 04:33 | That's going to be 10 to 1, instead of 1 to 10.
| | 04:38 | So the mole should pop up, stay up for
a second or so, and then go back down.
| | 04:43 | So let's save and test
again and see what we get.
| | 04:52 | So I'll click Play. You see the moles go up,
and after a little bit, they go back down.
| | 04:58 | I'll quit the simulator.
| | 05:06 | So now our game has more life because the
moles animate using frame-by-frame animations.
| | 05:13 | Remember that you can animate using a
CC animation of frames that's passed
| | 05:19 | into a CCAnimate action.
| | Collapse this transcript |
| Handling touches in the game| 00:01 | Now that the moles can animate up and
down, we'll look at how to handle touches
| | 00:05 | so that a mole will get hit when you tap it.
| | 00:08 | The first place to start is the
onEnterTransitionDidFinish method.
| | 00:12 | Remember that Game is a subclass of
CCScene and not CCLayer, so it's not
| | 00:19 | automatically set as a touch-handling delegate.
| | 00:22 | That means you don't receive touch-
handling events until you register the object
| | 00:28 | with the touch dispatcher.
| | 00:30 | So let's start by doing that.
| | 00:31 | At the top of onEnterTransitionDidFinish,
type some double brackets, and in inner
| | 00:37 | brackets, CCTouchDispatcher
sharedDispatcher, and in outer brackets,
| | 00:46 | addStandardDelegate--it's going to be self.
| | 00:48 | Remember, we set this object as a
delegate of the TouchDispatcher in the Game.h
| | 00:54 | file. And the priority is going to be 0.
| | 00:58 | On the next line, we are going to
set Multiple Touch to be enabled.
| | 01:01 | Double brackets again.
CCDirector sharedDirector.
| | 01:05 | After the brackets, type openGLView, and then
I am going to type one more set of brackets.
| | 01:12 | After openGLView, I am going to
type setMultipleTouchEnabled to YES.
| | 01:17 | Now let's scroll up to ccTouchesBegan.
| | 01:20 | Here the first thing we are going to do
is check to see if the game is paused,
| | 01:24 | and if so, we'll return.
| | 01:26 | So if isPaused and then just a return.
| | 01:28 | Remember, we don't want to be
handling any touches for the game when it's
| | 01:33 | not really running.
| | 01:34 | So first, we'll loop through all the touches.
| | 01:36 | Let's type for, and this time we
are going to do a for in loop.
| | 01:41 | It's going to be for UITouch
*touch in, brackets, event allTouches.
| | 01:52 | Inside of that loop, we're going to write
another for in loop to loop through the moles.
| | 01:56 | So for, and then it's going to be Mole, with a
capital M, and the iterator will be mole,
| | 02:03 | with a lowercase m, in moles--that's the array.
| | 02:08 | So capital M is the class, lowercase m is
the iterator object, and moles is the array.
| | 02:14 | Now we need to get the Touch location.
| | 02:17 | CGPoint location, set it equal to, in brackets,
touch locationInView:touch.view.
| | 02:31 | Next we'll convert this location
to something we can use in cocos2D.
| | 02:35 | So location equals, double brackets, CCDirector sharedDirector
convertToGL, then pass in the location.
| | 02:46 | Below that, let's put an if statement
that checks to see if the location is
| | 02:50 | touching the bounding box of the mole.
| | 02:53 | So inside of the if
statement, CGRectContainPoint.
| | 02:56 | The Rect is going to be the bounding
box of the mole, so, in brackets, mole boundingBox. And
| | 03:02 | the point is going to be the
location of the touch, so just location.
| | 03:07 | In the if statement, we want to
skip this mole if the mole is not up.
| | 03:11 | So type another if statement, and in that
inner if statement, type an exclamation
| | 03:19 | point, some brackets, type mole getIsUp.
| | 03:24 | So if the mole is down then we
don't want to tell it that it was hit.
| | 03:29 | So if that's the case then
we're just going to continue.
| | 03:32 | So we're going to go into
the next iteration of the loop.
| | 03:35 | Below that inner if statement, I am going to tell
the mole that it was tapped. So, in brackets, mole wasTapped.
| | 03:42 | Now let's just jump over to the mole class and
define what happens when the mole gets tapped.
| | 03:46 | Let's go to Mole.m and find wasTapped.
| | 03:51 | In here, we're going to only
do the code if the mole was up.
| | 03:54 | So we are double-checking. So if isUp,
then in here, we're going to start by
| | 04:01 | stopping all actions of self, stopAllActions.
| | 04:02 | It will stop every action that's
currently running. And then on the next line, we
| | 04:07 | will make them all animate
down, so self runAction:,
| | 04:11 | in brackets, CCAnimate actionWithAnimation--
make sure you choose the one that says
| | 04:17 | restoreOriginalFrame.
| | 04:19 | Animation is going to be in brackets,
self getAnimationwithFrames, 21 to 31,
| | 04:28 | restoreOriginalFrame is going to be NO,
and then on the next line, we'll set isUp
| | 04:33 | = NO, and that's it.
| | 04:36 | Now when you tap a mole, it
should play the hit animation.
| | 04:39 | So save and test the app in the simulator.
| | 04:48 | So I'll click Play at Main menu, and now
I can touch all the moles to hit them.
| | 04:52 | I'll quit the simulator.
| | 04:59 | So now it's starting to
feel like an actual game.
| | 05:03 | The moles animate up and down and
through touch-handling, we can tell if a mole
| | 05:09 | was touched and if so, it plays a hit animation.
| | 05:13 | And remember, if you are using a
subclass of CCScene as you main class, make
| | 05:19 | sure it's adopting the
CCStandardTouchDelegate protocol if you are going to
| | 05:23 | support multi-touch and that in
onEnterTransitionDidFinish you set the
| | 05:29 | CCTouchDispatcher sharedDiespatcher to
add the object as a standard delegate and
| | 05:35 | then setMultipleTouchEnabled through
the CCDirector, and then you can handle
| | 05:39 | touches using a ccTouchesBegan event.
| | Collapse this transcript |
| Displaying the player's score with bitmap fonts| 00:00 | When you are working with text fields
in cocos2d that constantly update, it's a
| | 00:05 | good idea to use something called a bitmap font.
| | 00:09 | Think about bitmap font as
a strike sheet of a font.
| | 00:13 | The texture is only loaded once, and
it saves a ton of memory when you are
| | 00:18 | changing the text in a label.
| | 00:20 | In the HelloWorld cocos2d app,
you see a CCLabelTTF created.
| | 00:26 | Anytime you change the text in that
label, a whole new label gets created.
| | 00:31 | So if you are running something like a
timer that shows text, you're going to be
| | 00:35 | wasting a ton of memory by creating
a new text field every single frame.
| | 00:41 | Again, bitmap fonts will save you memory.
| | 00:44 | To create a bitmap font, you
can use an editor like Hiero.
| | 00:47 | You'll have to look it up on the Internet,
and you can download and install it for free.
| | 00:55 | To use Hiero, choose a font that you
have installed on your computer, choose the
| | 01:00 | effects, choose the color,
any padding between characters,
| | 01:04 | you can preview the font here, and then
you could save the font as a .fnt file.
| | 01:10 | So you also want to save a .png file of image.
| | 01:15 | Sometimes when you save that PNG file,
it's flipped backwards, or upside down, and
| | 01:20 | you can just use the Preview app on
your computer to adjust it accordingly.
| | 01:24 | So I am going to jump back in to Xcode, and now
we will look at how to use one of these fonts.
| | 01:30 | So again, you are going to need the
.fnt file and the .png file to display the
| | 01:36 | text field so make sure to import those
into your project after you create them.
| | 01:41 | So right under where we add the sprites
and initialize game, I am going to type
| | 01:46 | int fSize, short for font size, = 24.
| | 01:52 | On the next line, we'll create the
scoreLabel by typing scoreLabel =, and in brackets,
| | 01:58 | CCLabelBMFont labelWithString--
String is going to be score:0. And the font
| | 02:08 | file is a string to the FNT file,
and I am going to use an NSString with
| | 02:14 | format to define that.
| | 02:16 | So brackets there instead of a
literal string, and NSString stringWithFormat.
| | 02:25 | That's going to be %i.fnt", fSize.
| | 02:36 | On the next line, we'll set the anchor
point to 01 because we want the score
| | 02:41 | label to be at the top left.
| | 02:42 | So scoreLabel.anchorPoint = ccp(0,1).
That will give it a top-left anchor point.
| | 02:53 | One the next line, we'll set
the scorelabel's position.
| | 02:56 | So scoreLabel.position = ccp, and
parentheses will pass in 0, which will hug it
| | 03:05 | against the left edge of the screen,
and then s.height, which will bring it all
| | 03:10 | the way up to the top edge of the screen.
| | 03:13 | Then we'll add it to the
screen by typing self addChild:
| | 03:16 | scoreLabel, and the z position is going to be 10.
| | 03:23 | Now let's scroll down to ccTouchesBegan.
| | 03:28 | After a mole was tapped, go to the next
line, and in brackets, type self didScore.
| | 03:37 | Scroll down to the didScore method,
and here we'll increment score by 1, so
| | 03:42 | score++. And then on the next line,
we'll set the score label string.
| | 03:48 | So, in brackets, scoreLabel setString,
and string is going to be another
| | 03:55 | NSString with format, so NSStringWithFormat.
| | 04:02 | That's going to be score: %i. After the close quote,
type a comma and then type score.
| | 04:11 | So it will show score:
and then the score at the top of the screen.
| | 04:18 | Your score will increase
each time you hit a mole.
| | 04:20 | Save and test this in the simulator.
| | 04:22 | So I'll click the Play button and each
time I hit a mole, you should see the score
| | 04:33 | increase at the top-left of the screen. Nice!
| | 04:38 | I'll quit the simulator.
| | 04:41 | So just remember, bitmap fonts
are like sprite sheets for fonts, and you
| | 04:45 | save a ton of memory because you don't
have to create a label every time you
| | 04:49 | change the string.
| | Collapse this transcript |
| Handling misses| 00:00 | To increase the intensity of the game,
it's important to make a way for you to lose;
| | 00:05 | you lose the mole game by missing three moles.
| | 00:09 | So let's a take a look at how to handle that.
| | 00:12 | Remember, the mole class sends a missed
mole message if you don't hit the mole in time.
| | 00:17 | So we just need to handle missed mole
in the game class to decide what happens
| | 00:21 | when a mole is missed.
| | 00:23 | So in here the first thing we are
going to do is subtract from carrotsLeft.
| | 00:27 | So carrotsLeft, two minus signs, and then
on the next line if, and in brackets, carrots count > 0,
| | 00:36 | then we are going to remove that carrot.
| | 00:43 | So self, removeChild, and the child is
going to be, in brackets, carrots objectAtIndex, and
| | 00:54 | then some more brackets, and in the
brackets, carrot count, outside of the brackets
| | 01:01 | -1, so the last index of that array.
Then under cleanup, we will put YES.
| | 01:09 | And then on the next line, we'll remove
the last object from the carrots array.
| | 01:15 | So carrots removeLastObject.
| | 01:19 | Then we will check to see if carrots
left is less than or equal to zero.
| | 01:28 | If so, we will run gameOver.
| | 01:30 | Now gameOver doesn't do anything just
yet; we are just setting it up for later.
| | 01:35 | So in brackets, self gameOver and
then the else statement below that if
| | 01:39 | statement, we are going to
tell all the moles to stop early.
| | 01:43 | So for, this is going to be a for in
loop, so it's going to be a mole called "m",
| | 01:52 | in brackets, self getUpMoles.
| | 01:56 | That's all the moles that are up and in
brackets in the for a loop, m stopEarly.
| | 02:03 | So we'll make all the moles
go down if you miss one.
| | 02:06 | So save and test in the simulator, and
you should see that each time you miss a
| | 02:10 | mole, a carrot disappears and they all go down.
| | 02:13 | Now you won't see anything
when you actually get a gameOver.
| | 02:17 | We will define that later on.
| | 02:22 | So I'll click Play. You can hit a mole
but if you miss, they all go down.
| | 02:29 | And notice that the carrots disappear as well.
| | 02:36 | So now it's feeling more and more like a game.
| | 02:39 | Whenever you miss the mole, one of the
carrots disappears and all the moles go down.
| | 02:45 | Remember, you can take an
object off of the screen by using the
| | 02:48 | removeChild method.
| | Collapse this transcript |
| Detecting double taps| 00:00 | We have already set up the functionality for
the green moles which require a single tap.
| | 00:05 | Now we will look at adding the
blue moles which require a double-tap.
| | 00:10 | Let's start by going to the tick
method and at the very bottom, we will type
| | 00:13 | canShowBlueMoles and set it equal to YES.
| | 00:18 | Then in chooseWhichMoleToMake, after
the equals sign, after nextMoleType, we're going
| | 00:23 | to type CCRANDOM_0_1.
| | 00:27 | That's all caps, and that
gives us a number between 0 and 1.
| | 00:30 | Then we will check to see if it's less
than .15. That means a 15% chance that
| | 00:37 | a blue mole will show. And, so two
ampersands, canShowBlueMoles and a question
| | 00:44 | mark after the parentheses. Then type MOLE_TYPE
_B, all caps, then a colon after MOLE_TYPE_B.
| | 00:54 | Now let's scroll down to ccTouchesBegan.
| | 00:57 | In here we want to detect a double-tap.
| | 00:59 | So right above mole wasTapped and self
didScore, I am going to type bool, type
| | 01:06 | greenMoleWasWhacked. We will
set it equal to, in parentheses, in brackets, mole getType,
| | 01:22 | put some out brackets around those brackets, is
EqualToString:MOLE_TYPE_A;
| | 01:30 | After the parentheses, just
make sure to put a semicolon.
| | 01:33 | Let's copy and paste that Boolean
statement to the next line, change
| | 01:39 | greenMoleWasWhacked to
blueMoleWasWhacked, and then we are going to check to
| | 01:44 | see if the mole was MOLE_TYPE_B so
change the A to B. And then before the end
| | 01:51 | of the parentheses, type two ampersands,
and then we are going to check to see
| | 01:57 | if it's a double-tap.
| | 01:58 | To do that, we just use the method
tap count of the UI touch to get the
| | 02:03 | number of taps that occurred.
| | 02:05 | So, in brackets, touch tapCount, outside the brackets, > 1.
| | 02:13 | So if its MOLE_TYPE_B, and if the tap count is
greater than 1, then a blue mole was whacked.
| | 02:19 | Now I am going to wrap mole wasTapped
and self didScore in an if statement.
| | 02:25 | So type if and put some parentheses.
In there, we'll check to see if a green
| | 02:31 | or a blueMoleWasWhacked.
| | 02:32 | So if (greenMoleWasWhacked ||
blueMoleWasWhacked) then we will tell the mole
| | 02:41 | that it was tapped and that we scored.
| | 02:44 | So, we'll just cut and paste mole wasTapped and
self didScore inside of that if statement.
| | 02:51 | Now let's save and test the app.
| | 02:53 | We should see that 15% of the moles are
blue and that you can only knock out a
| | 02:58 | blue by double-tapping it. So click Play.
| | 03:07 | So green moles, and they take a single tap
still and then blue moles, you tap them once,
| | 03:14 | they don't do anything.
| | 03:15 | We tap them twice pretty quick and then go down.
| | 03:26 | Now we've successfully handled a double-tap.
| | 03:30 | So remember that you can access the
amount of taps by the touches tapCount
| | 03:35 | method, and that returns an integer
that will tell you how many times an
| | 03:39 | object was tapped.
| | Collapse this transcript |
| Detecting simultaneous taps| 00:00 | Now we will add the yellow moles that
must be tapped simultaneously. Scroll to
| | 00:05 | the tick method. After
canShowBlueMoles is set to YES, set canShowYellowMoles
| | 00:12 | equal to YES and scroll up.
And to choose which mole to make,
| | 00:17 | set nextMoleType right below where
we set it before, equal to MOLE_TYPE_C.
| | 00:26 | On the next line, I want to it
call to self showMole again.
| | 00:30 | We are going to create two at a
time when we create yellow moles.
| | 00:35 | Now scroll down to
ccTouchesBegan. Right below the if statement where
| | 00:38 | we are trying to see if it's paused, create an
NSMutableArray and call it molesTappedAtOnce.
| | 00:49 | Now we will just initialize the
array using NSMutableArray alloc and init.
| | 00:59 | Find the if statement that checks to
see if the mole is not up. Right before
| | 01:04 | the close parenthesis,
type || for an OR statement.
| | 01:09 | We also want to continue the loop if
the molesTappedAtOnce array already
| | 01:14 | contains the mole that we are looking at.
| | 01:17 | So, in brackets, molesTappedAtOnce containsObject:mole).
| | 01:27 | Below this if statement we are going to
create another if statement and check to
| | 01:30 | see if a yellow mole was tapped.
| | 01:35 | So in the if statement, in double brackets, in the inner brackets,
(mole getType isEqualToString:MOLE_TYPE_C) then we are
| | 01:49 | going to add this mole to
the molesTappedAtOnce array.
| | 01:53 | So, in brackets, molesTappedAtOnce addObject:mole.
Now scroll down and outside of the for loop,
| | 02:04 | which goes through all the touches, so
right above the end of this method, check
| | 02:10 | to see if molesTappedAtOnce has
a count that's greater than 1.
| | 02:14 | So if statement, and then in brackets (molesTappedAtOnce
count > 1). If so, that means that more than 1
| | 02:27 | mole was tapped at the same time.
| | 02:28 | So we are going to loop through all
those moles using a for in loop, so for
| | 02:35 | (Mole *m in molesTappedAtOnce) and
then in the for loop m wasTapped;
| | 02:48 | on the next line, self didScore.
| | 02:51 | Below that if statement, we
are going to remove all objects
| | 02:55 | from molesTappedAtOnce.
| | 03:00 | At this point, you can save and
test to make sure the yellow moles are
| | 03:03 | appearing in simulator, but you won't be
able to hit them because you don't have
| | 03:08 | fine control over multi-touch in the simulator.
| | 03:11 | So really, all you can do is a pinch.
| | 03:15 | So you will need to test it on your own
device at this point to make sure that
| | 03:19 | the yellow moles are working properly.
| | 03:20 | So there are the yellow moles, and they are
appearing two at a time, and they disappear.
| | 03:27 | So I will quit the simulator and
just remember, you can handle multiple
| | 03:32 | touches at the same time by storing the
objects in an array and then after you
| | 03:39 | loop, where you loop through all the
touches, check to see if that array has
| | 03:43 | a count greater than one. Then you can
send the appropriate messages to all the
| | 03:48 | objects in the array.
| | Collapse this transcript |
| Controlling the number of moles on the screen at once| 00:00 | Most games start out relatively
easy and get more difficult as they go.
| | 00:06 | Now we'll add that feature to our game
by adding more moles and different types
| | 00:11 | of moles as the game goes on.
| | 00:14 | In the init method you'll see
molesAtOnce is set to 3, timeBetweenMoles is set
| | 00:19 | to 0.5, and increaseMolesAtTime is set to 10.0.
| | 00:23 | We will use these properties together
to make the game start out easy with just
| | 00:28 | green moles, eventually add blue
and yellow moles as the game goes on.
| | 00:33 | So scroll down to the tick method.
| | 00:37 | In the tick method, we're going to add onto
increaseElapsed by the amount of Delta Time.
| | 00:43 | That's DT.
| | 00:45 | So type increaseElapsed += dt.
| | 00:49 | Below the if statement that checks to
see if timeElapsed >= timeBetweenMoles, go
| | 00:55 | to the next line and then create a
new if statement that checks to see if
| | 01:01 | increaseElapsed >= increaseMolesAtTime.
| | 01:07 | If so, we're going to
make the game more difficult.
| | 01:10 | The first thing we'll do is define how
many moles we can have at once on the screen.
| | 01:14 | So create an integer called
maxMolesAtOnce and set it equal to 18.
| | 01:22 | So that's the max amount of moles that
can possibly be on the screen at one time.
| | 01:27 | Now, an if statement:
| | 01:28 | if (molesAtOnce < maxMolesAtOnce) then
we'll increment molesAtOnce. So molesAtOnce++.
| | 01:41 | Then we'll go to the next line,
create a float called minMoleTime.
| | 01:46 | This will represent the minimum amount
of time between one mole popping up and
| | 01:51 | another mole popping up.
| | 01:52 | We'll set this equal to .1f.
| | 01:56 | Now, in the next line we're going to
subtract from the timeBetweenMoles.
| | 02:01 | So as the game gets more difficult,
there's less time between moles popping up.
| | 02:05 | So timeBetweenMoles -= and in
parentheses, we're going to check to see if
| | 02:13 | timeBetweenMoles > minMoleTime.
| | 02:16 | Now, if so, I'll put a
question mark and type 0.05f.
| | 02:24 | So we'll subtract from it in a very
small amount each time the game gets more
| | 02:29 | difficult, and put a colon. And if it's
already reached the minimum mole time,
| | 02:36 | we're going to modify it by
nothing. So just put a 0.
| | 02:41 | Go to the next line and then
type increaseMolesAtTime += 10.0f.
| | 02:48 | That will make the game gradually get harder.
| | 02:51 | So the first time it happens is after 10
seconds, then the next time is after 20
| | 02:55 | seconds, and the time after
that it's after 30 seconds.
| | 02:58 | Now, below that if statement, we'll
create another if statement--remember we're
| | 03:03 | still in increaseElapsed >= increaseMolesAtTime.
| | 03:08 | So this if statement is going to
check to see if canShowBlueMoles is true.
| | 03:11 | I am just going to cut and paste
canShowYellowMoles = YES, put that right inside
| | 03:18 | of that if statement,
| | 03:20 | and below the if statement we just
wrote, we'll create an else statement, and
| | 03:23 | then we'll cut and paste
canShowBlueMoles = YES into the else statement.
| | 03:30 | So the first time this runs,
canShowBlueMoles will be NO.
| | 03:34 | So it'll run the else statement, set it to YES.
| | 03:36 | When it runs again, canShowBlueMoles will be
YES, so canShowYellowMoles will be set to YES.
| | 03:42 | So let's scroll up to choose which
mole to make to control which mole shows.
| | 03:48 | Remember, this is where we're going to
control whether or not a mole gets made,
| | 03:55 | because each time timeElapsed >=
timeBetweenMoles, as stated in the tick method,
| | 04:02 | we're going to run chooseWhichMoleToMake.
| | 04:03 | So what we're going to do in here is, if
there are too many moles on the screen,
| | 04:08 | just back out of this method entirely.
| | 04:11 | So the first thing we want to do in
chooseWhichMoleToMake is write an if
| | 04:14 | statement. And in the if statement, type
some brackets and type self getMolesUp.
| | 04:20 | Remember, that returns an
integer of moles that are up.
| | 04:22 | We're going to check to see if that's
greater than or equal to molesAtOnce.
| | 04:25 | Now, if there are already too many
moles on the screen, and we just want to
| | 04:30 | get out of this method, so we'll do
return. And then we have nextMoleType set
| | 04:36 | to be RANDOM for the blue moles, and we
have a check for canShowBlueMoles, so
| | 04:42 | that's already good.
| | 04:43 | We just need to modify how we show yellow mole.
| | 04:45 | So let's go to the next line and type if.
| | 04:48 | In the if statement we want to see if we
have enough space in the moles that can
| | 04:53 | be on the screen to allow two moles to pop up.
| | 04:57 | So in brackets, self getMolesUp, and then
out of the brackets is < molesAtOnce - 1.
| | 05:07 | So in other words, we have enough
space to put two moles up at once.
| | 05:11 | And we want to make sure that there's
a small chance that this happens, so
| | 05:15 | CCRANDOM_0_1() < .1. And, so two
more ampersands, canShowYellowMoles.
| | 05:28 | Now, if that's the case, we're just
going to cut and paste nextMoleType =
| | 05:32 | MOLE_TYPE_C and self showMole, and place it
right inside that if statement we just wrote.
| | 05:38 | So if all the appropriate conditions
are met, we show a yellow mole or else we
| | 05:43 | show a blue or a green mole.
| | 05:46 | So let's play the game in the simulator.
| | 05:48 | Now, when you play the game, you want
to look for seeing only green moles at
| | 05:56 | first, and after 10 seconds, you should
see the blue moles start popping up, and
| | 06:01 | after 20 seconds from there, you
should see the yellow moles popping up.
| | 06:05 | So I will click to play the game,
and at the beginning, we see only green
| | 06:10 | moles, and then after about 10 seconds, you
should start to see blue moles start appearing.
| | 06:17 | Now, if it doesn't happen at first,
just give it some time, because it's random.
| | 06:24 | So there is the blue moles,
and we have the yellow moles too.
| | 06:26 | I will quit the simulator.
| | 06:31 | So you see, the game gets
harder and harder as you go.
| | 06:34 | You may have also noticed as you were
playing that more and more moles are
| | 06:38 | appearing on the screen at
the same time as time goes on.
| | 06:41 | So we've successfully created a
game that starts out easy and gets more
| | 06:47 | difficult as time goes on.
| | Collapse this transcript |
| Adding sound| 00:00 | Now we will add sound
effects and music to the game.
| | 00:03 | Go to your initializeGame method, and
right under where we set the value for s,
| | 00:08 | we'll set the value of missSound.
| | 00:11 | This is a string, and it's going to
be the name of the sound that happens
| | 00:15 | when you miss a mole.
| | 00:16 | So to set it, I'm going to use an
NSString stringWithFormat, and the format is
| | 00:24 | going to be %@_miss.wav",
delegate getCurrentSkin.
| | 00:39 | That way whenever we change the skin,
it will either play mole_miss.wav
| | 00:45 | or jetpack_miss.wav.
| | 00:48 | So I created the game from the
beginning to support this skinning feature.
| | 00:51 | So let's just copy and paste this
line of code to the next line, change
| | 00:56 | missSound to hitSound, and adjust the
string to say _ouch instead of _miss.
| | 01:05 | Now let's preload all of the effects.
| | 01:07 | So go down a few lines, double
brackets, and in the inner brackets,
| | 01:13 | type SimpleAudioEngine.
| | 01:14 | You may have to import this class, if
you haven't already. Space, sharedEngine.
| | 01:19 | In the outer brackets,
preloadEffect, and we will pass in missSound.
| | 01:24 | We can copy and paste this
line and preload hitSound.
| | 01:34 | Paste the line again on the next line,
and instead of missSound, we will change
| | 01:39 | this to a literal string, splat.wav.
| | 01:43 | We're going to use the
splat sound for both skins.
| | 01:47 | Paste the code one more time and change
preloadEffect to preloadBackgroundMusic.
| | 01:55 | Here we'll type some brackets,
and then NSString stringWithFormat.
| | 02:02 | This is going to be %@_bg.mp3, and then
again after the close quote, comma, and
| | 02:11 | then brackets, delegate getCurrentSkin.
| | 02:14 | Now, all this does is preload the sound
effects so that when they first occur,
| | 02:18 | there won't be any kind of a delay.
| | 02:20 | So all the delay will be
preloaded before the scene itself loads.
| | 02:26 | Now let's look at playing the sounds.
| | 02:28 | The first thing I am going to
do is play the background music.
| | 02:32 | So I am going to copy the line of
code that says preloadBackgroundMusic.
| | 02:36 | I am going to scroll down to
startGame. Right above self
| | 02:41 | schedule:@selector(tick:), I'm
going to paste that code and change
| | 02:45 | preloadBackgroundMusic to playBackgroundMusic.
| | 02:49 | Right before the last close bracket,
I'm going to type a space, and then I'm
| | 02:52 | going to type loop, and
then I'll type YES in all caps.
| | 02:56 | That way, the background music will loop
over and over again as you play the game.
| | 03:01 | Now let's scroll to ccTouchesBegan,
and we'll add in the hit sound effects.
| | 03:11 | So right under mole wasTapped and self
didScore in the if statement that checks
| | 03:16 | if a green or blue mole was whacked,
let's go down a few lines, some double
| | 03:22 | brackets, inner bracket,
SimpleAudioEngine sharedEngine and then playEffect, and
| | 03:29 | we can choose the one with pitch, pan, and gain.
| | 03:32 | That way we can control the pitch,
panning, and volume of sound.
| | 03:36 | So the effect is going to be
hitSound. The pitch will be 1.
| | 03:42 | If you want to randomize it,
you could put a CC_RANDOM right here.
| | 03:46 | Pan will be 1, and gain will be .25.
| | 03:55 | This is a value that goes from 0,
which is completely off, and 1, which
| | 04:00 | is normal, full volume.
| | 04:02 | So you can adjust this
to whatever you want here.
| | 04:04 | Go to the next line.
| | 04:05 | I'll do the same thing:
| | 04:09 | double brackets, inner brackets, access
the sharedEngine of SimpleAudioEngine,
| | 04:14 | and then we'll playEffect. And instead
of the one with pitch, pan, and gain,
| | 04:18 | we're just going to use the
one that requires a string.
| | 04:23 | And the effect will be a literal string,
splat.wav. Copy and paste these two
| | 04:30 | lines of code in the line of
code where we detect yellow moles.
| | 04:34 | Now, I'm not going to put this in the loop.
| | 04:37 | I don't want two sound effects to
happen when you hit two moles at the same
| | 04:40 | time; I just want one sound effect.
| | 04:42 | So that's going to go under the for loop,
but inside of that if statement that
| | 04:46 | checks to see if
molesTappedAtOnce's count is above 1.
| | 04:51 | Now let's scroll down to missedMole,
and we'll play a sound there as well.
| | 04:56 | Right under carrotsLeft--, paste the
code, delete the line of code that says
| | 05:03 | splat, change the effect to missSound,
change the gain to .2, and that's it
| | 05:13 | for adding the effects.
| | 05:14 | What we want to do to preserve memory is to
unload the effects when the scene unloads.
| | 05:19 | We can do that in the onExit method.
| | 05:21 | So scroll down to there, and under
carrots release and moles release, we'll
| | 05:27 | paste in the code that we copied earlier.
| | 05:31 | We'll change playEffect to unloadEffect,
and we'll do this for hitSound and missSound.
| | 05:37 | So I'll just copy and paste that and
change hitSound to missSound in the pasted code.
| | 05:44 | And in playEffect:@"splat.wav",
I'll unload that effect.
| | 05:48 | So at this point you should be able to test
the app and hear the sound effects and music.
| | 05:55 | So on the simulator, when you play the
game, you should be able to click on a
| | 05:59 | mole and hear the hit sound;
| | 06:02 | miss a mole, and when the carrot
disappears, hear the miss sound;
| | 06:06 | and you should hear the splat sound
when you hit a mole, and you should hear
| | 06:10 | the background music.
| | 06:11 | So I'll click to play the game.
(audio playing)
| | 06:17 | When I hit the mole, you hear the hit sound;
| | 06:19 | when I miss, you hear the miss sound;
| | 06:21 | and in the background, you
hear the background music.
| | 06:24 | Now that our game has sound effects
and music, it has more life, and it feels
| | 06:32 | more like a game than ever.
| | Collapse this transcript |
| Enabling a pause feature| 00:01 | Have you ever played a game
that didn't have a pause feature?
| | 00:04 | Even a short game, like the game we're
making here, can use pause, because you
| | 00:09 | never know when someone might be
competing for the highest score, and they've
| | 00:13 | been playing for two hours straight,
and they don't want the game to end, but
| | 00:17 | they get a call or some other
thing that makes the gameplay stop.
| | 00:22 | You don't want to throw out all their progress.
| | 00:24 | So let's take a look at how to pause the game.
| | 00:27 | So in the pauseGame method in the game
class, the first thing I am going to do
| | 00:31 | is check if the game is paused.
| | 00:35 | If the game is paused,
I am just going to return.
| | 00:38 | So if(isPaused) and then return.
| | 00:42 | Next, we will make the Pause menu.
| | 00:44 | So CCmenuItemSprite. We'll call this
first one resumebutton, and we will set it
| | 00:53 | equal to, in brackets, CCmenuItemSprite,
itemFromNormalSprite, selectedSprite,
| | 01:00 | target selector--make sure you choose that one.
| | 01:02 | The NormalSprite is going to be in
brackets, Gamebutton buttonWithText, and then
| | 01:10 | pass in the text as a string.
| | 01:12 | So it will be resume.
| | 01:14 | This font is all caps, so it doesn't
matter if you put capital or lowercase letters.
| | 01:18 | So I am putting all lowercase for this,
and now it's set selectedSprite to NULL,
| | 01:23 | target is going to be self, and that
selector is going to be resumeGame.
| | 01:31 | Copy and paste this line of code to
the next line, change resumebutton to
| | 01:37 | mainbutton, change the text to main menu,
change the selector to mainmenu, with a capital M.
| | 01:50 | Now, we'll create the
menu and add these buttons.
| | 01:54 | Make sure you use CCmenuPopup.
| | 01:56 | We'll call this menu, set it equal to,
in brackets, CCmenuPopup menuWithItems,
| | 02:06 | pass in the resumebutton and
then the mainbutton and then nil.
| | 02:12 | On the next line, in brackets, type menu
alignItemsHorizontallyWithPadding and pass in 10.
| | 02:21 | Now, we will create the pop-up menu itself.
| | 02:23 | Data type is PopUp.
| | 02:25 | We will call this pop, set it equal
to, in brackets, PopUp popUpWithTitle
| | 02:34 | description and sprite.
| | 02:37 | Title is going to be
"pause" in the middle of hyphens.
| | 02:40 | The description is just going to be an empty
string, and the sprite is going to be the menu.
| | 02:49 | We'll add the pop-up as a
child by calling self addChild.
| | 02:51 | I will pass in pop, give it a z of
1000 so it's in front of everything.
| | 02:57 | That we'll hide the pause button, so we
can set it to visible property to NO.
| | 03:02 | We'll make all the moles stop early, so
we'll use a for in loop for that. So for
| | 03:10 | (Mole *m in self getUpMoles, and we'll send the
message to m to stop early. So m stopEarly.
| | 03:25 | On the next line, we will
unschedule the tick selector.
| | 03:27 | So self unschedule:@selector (tick).
We will pause the background music.
| | 03:35 | So, inner brackets, SimpleAudioEngine sharedEngine,
and outer brackets, pauseBackgroundMusic,
| | 03:44 | and set isPaused = YES.
| | 03:47 | Now in resumeGame, we'll just
copy the last several lines from
| | 03:53 | pausebutton.visible = NO all
the way to the bottom of pauseGame.
| | 03:57 | I will paste them into resumeGame.
| | 04:00 | I will delete that for loop in
resumeGame, change pausebutton.visible to YES,
| | 04:08 | change self unschedule to self
schedule, change audio engine
| | 04:13 | pauseBackgroundMusic to
resumeBackgroundMusic, and set isPaused = NO.
| | 04:18 | Now, you should be able to test the
game in the simulator and be able to pause
| | 04:23 | and resume the game.
| | 04:28 | So I will click Play to play the game.
| | 04:30 | You hear the background music.
(audio playing)
| | 04:33 | I will click Pause. The background
music stops; the Pause menu shows up.
| | 04:38 | I see the Resume and Main menu buttons.
| | 04:40 | I can click Resume and the game resumes.
(audio playing)
| | 04:43 | I can pause it again.
| | 04:45 | I can click Main menu and
return to the Main menu.
| | 04:48 | So I'll close the simulator, and now
we've successfully added a pause feature.
| | 04:52 | So manly what we did is we stopped
running that tick selector, we told all the
| | 04:58 | moles to stop, and we set isPaused =
YES. And the TouchHandlers, and in some
| | 05:04 | other methods, we return
automatically if isPaused is set to YES.
| | 05:09 | And that way, the game is
completely frozen when we choose to pause it.
| | Collapse this transcript |
| Ending the game and saving the high score| 00:00 | Now we'll finish the main part of the
game by creating a gameOver screen and
| | 00:06 | allowing the pLayer to restart from the
beginning, and we'll also look at saving
| | 00:10 | the high score to the device.
| | 00:12 | We're already calling gameOver
when all the carrots are gone,
| | 00:16 | so all we need to do is
define the gameOver method.
| | 00:19 | I am going to start with copying and
pasting all the code in the pauseGame
| | 00:23 | method that's under the if
statement at the beginning.
| | 00:26 | I'll paste that into the gameOver
method, and we'll make a few modifications.
| | 00:32 | The first thing I'll do is just cut and
paste all the code that doesn't have to
| | 00:36 | do with the menu, to the top of the method.
| | 00:42 | So before anything else, we're going to
stop all of the interactivity in the game.
| | 00:45 | I am not worried about hiding the
pausebutton here, so I am just going to
| | 00:49 | delete that line of code.
| | 00:51 | And instead of looping through all the
moles that are up, I am going to loop
| | 00:55 | through all the moles that were
created by looping through the moles array.
| | 01:01 | And for each mole in there, I am going to
delete stopEarly and tell it to stopAllActions.
| | 01:08 | And then I'm going to tell each
mole to unscheduleAllSelectors.
| | 01:13 | Below the for loop, tell delegate that
we finishedWithScore, and I'll pass in
| | 01:19 | the final score, which is in the score property.
| | 01:23 | I'll change unscheduled:@selector (tick:)
| | 01:25 | to unscheduleAllSelectors, and
I'll change pausebackgroundMusic to
| | 01:29 | stopBackgroundMusic.
| | 01:32 | And I'll delete isPaused equals YES.
| | 01:37 | Now we'll modify the code for the menu.
| | 01:40 | We still want the Mainmenu button, but
we're going to change the resumebutton to
| | 01:44 | the playAgainbutton.
| | 01:46 | So I'll change resumebutton's
variable name to playAgainbutton.
| | 01:52 | I'll change the
resumeGame selector to playAgain.
| | 01:54 | That will run the playAgain method,
which will reload the game scene.
| | 01:59 | And finally, I'll change the text for
the playAgain button to be play again.
| | 02:05 | And now, when creating the menu,
I'll have to change resumebutton
| | 02:09 | to playAgainbutton.
| | 02:10 | And in the PopUp, I'll change
the Title to game over from pause.
| | 02:14 | Now, the high score already displays on
the Mainmenu, so we just need to update
| | 02:19 | the delegate's high score in the
finishedWithScore method and make sure that we
| | 02:23 | save this score to the device.
| | 02:26 | So let's go over to AppDelegate.m
and find finishedWithScore.
| | 02:30 | I'm going to Command+Click the Method
Selector at the top of the screen and
| | 02:36 | choose finishedWithScore.
| | 02:38 | Command+clicking that menu
allows you to go to your selectors in
| | 02:42 | alphabetical order.
| | 02:45 | So here we can check the high
score retained by the device in the
| | 02:49 | getHighScore method.
| | 02:50 | That grabs the value from the UserDefaults.
| | 02:53 | So in here let's write an if
statement to check to see if score is greater
| | 02:58 | than the high score.
| | 02:59 | So if score is greater than, and in
brackets, self getHighScore, then we're going
| | 03:06 | to save the high score to the device.
| | 03:09 | So in double brackets, NSUserDefaults,
standardUserDefaults. In the outer
| | 03:15 | brackets, setInteger, and the integer
is going to be score, forKey, and the key
| | 03:22 | will be kHighScoreKey. And that's it.
| | 03:26 | And remember that in the Mainmenu, we have a
reference to the High Score in the High Score label.
| | 03:35 | So we're referencing delegate's High
Score and putting it in that label.
| | 03:40 | Before we test it, we're going to do
one more thing in the Game class, and at
| | 03:44 | the very bottom, in the onExit method,
we're going to do something to optimize
| | 03:50 | memory, and that's where we're going to
disconnect the Game class from being a
| | 03:56 | delegate of the TouchDispatcher.
| | 03:59 | So double brackets, and in the inner brackets,
| | 04:02 | CCTouchDispatcher sharedDispatcher;
| | 04:05 | in the outer brackets,
removeAllDelegates. And that will just make sure that
| | 04:12 | the TouchDispatcher is not holding
on to an old instance of the game.
| | 04:15 | So this will completely finish our
main portion of the game, and now we'll
| | 04:20 | test it in simulator.
| | 04:21 | So you see High Score is 0 here.
| | 04:29 | I'll play the game.
(audio playing)
| | 04:31 | We get a High Score of 1, and at the
end you'll see the Game Over screen, and
| | 04:36 | from the Game Over screen, I can return
to the Main menu and see that my High
| | 04:40 | Score is saved as 1.
| | 04:41 | I'll click to Play.
| | 04:45 | I can play the game
again and get a higher score.
| | 04:47 | And from the Game Over menu, I am going
to click to Play again, and then I can
| | 04:56 | return to the Main menu, and I'll see
that my High Score is now 2, which is the
| | 05:00 | second highest score that I got
when I played the game the second time.
| | 05:04 | So I'll close the simulator, and now
we have successfully finished the basic
| | 05:09 | gameplay of our game.
| | 05:11 | So just remember that you can save and
display high scores using simple calls
| | 05:15 | to user defaults.
| | Collapse this transcript |
|
|
4. Expanding Your Game's Features and AudienceAdding custom skins| 00:00 | Skins are one feature that adds to the
replay value of your game because you
| | 00:05 | get different art, and it almost feels
like you're playing an entirely different
| | 00:09 | game when you just have a new skin.
| | 00:12 | Throughout this course, up to this
point, we have designed just about
| | 00:15 | everything to support skins.
| | 00:17 | You'll remember that in the game class
all the sound effects are based on the
| | 00:22 | current skin--same thing for the
background art and the main sprites.
| | 00:27 | You'll notice in the Art folder, in
the Resources folder, that there is
| | 00:32 | jetpack.plist for the jetpack sprites and
there's mole.plist for the moles sprites.
| | 00:38 | All we have to do is adjust the
delegate's current skin property and we have
| | 00:42 | different art in the game.
So let's go to the Main menu to do that.
| | 00:47 | The skins button in the main menu runs
the select skin method. This method shows
| | 00:52 | the different skin icons and runs the
selectors jSkin and moleSkin for the
| | 00:58 | jetpackSkin and the moleSkin
respectively, so let's scroll down, and jSkin and
| | 01:04 | mSkin will tell the
delegate to set the new skin.
| | 01:08 | So in jSkin, in brackets, delegate
setCurrentSkin. It's just going to be
| | 01:16 | SKIN_JETPACK, and the same thing
for mSkin: in brackets, delegate
| | 01:23 | setCurrentSkin SKIN_MOLE.
| | 01:27 | So if you test the app in the
simulator, you should see that you can click on
| | 01:32 | the skin's button, change the skin to the
alien skin--you'll see that reflected in gameplay.
| | 01:37 | Now if you're wondering why I called
the alien skin jetpack, it's because it's
| | 01:44 | based on it another game I
made called Jetpack Handyman.
| | 01:48 | So here's the alien. Click the Play
button and then we have the alien skin.
| | 01:54 | So there's green ones, and after a while
you'll see blue ones and then yellow ones
| | 02:00 | come up. So back to the main menu and
if I click Skins again, I can click on the
| | 02:07 | Mole and the game has the moleskin.
| | 02:10 | So I close the simulator.
| | 02:18 | So if you want to support skins in
your game, it's best if you plan ahead and
| | 02:22 | you have all the files named
accordingly, and then all you have to do is make
| | 02:27 | simple calls to the delegate to
set the current skin to the new skin.
| | Collapse this transcript |
| Asking players to rate the game| 00:00 | A good rating in the App Store
can make or break your sales.
| | 00:04 | In order to get your customers to rate
your game, you might have to remind them
| | 00:09 | when they're playing it.
| | 00:10 | Let's take a look at how to do that.
| | 00:12 | The AppDelegate class
implements the alertView protocol.
| | 00:17 | In alertView clickedbuttonAtIndex
handler, I have it set to return if
| | 00:23 | the buttonIndex is 0.
| | 00:25 | If it's not 0 then I open a link to
my game, which I copied from my iTunes
| | 00:31 | Connect page, and then I set the value Yes
for the kDidRate key in the user defaults.
| | 00:37 | So let's look at how to show this
alert by going to finishWithScore.
| | 00:43 | So I'll move to that method.
| | 00:44 | I'm going to write the code right
below this if statement. And here I'll
| | 00:50 | increase timesPlayed by 1, and I'll the save
the amount of times played in user defaults.
| | 00:57 | So double-brackets, NSUserDefaults
standardUserDefaults setInteger timesPlayed
| | 01:05 | forKey, and the key is going to be
kTimesPlayed. And then I'm going to ask the
| | 01:13 | user to review the game
every 10 times they play.
| | 01:16 | So if (timesPlayed % 10 = 0), that'll
mean if timesPlayed divided by 10 has a
| | 01:30 | remainder of 0--so if it's a
multiple of 10--then we're going to ask the
| | 01:34 | pLayer to rate the game.
| | 01:36 | We also want to make sure
they didn't already rate it.
| | 01:38 | So && !, and in double brackets, NSUserDefaults
standardUserDefaults boolForKey: kDidRate.
| | 01:51 | So they didn't rate the game, and then
they played it a multiple of 10 times.
| | 01:57 | If so, we want to ask them to rate the game.
So we'll create the alertView. It's UIAlertView.
| | 02:02 | We'll call this alert, set it equal
to, in double brackets, UIAlertView.
| | 02:10 | I'll allocate it and use initWithTitle,
and the title is going to be "Like Mole It?"
| | 02:21 | and then the message will be, "If you like
Mole It, please rate it to show your support."
| | 02:33 | Delegate will be self,
cancelbuttonTitle will just be Cancel, otherbuttonTitles
| | 02:41 | will just have one, will be Rate,
and then we'll show the alert.
| | 02:46 | So, on the next line, in brackets, alert show.
| | 02:51 | Now, of course we want it to have in
every 10 times, but just for testing
| | 02:55 | purposes, let's change that to 2,
timesPlayed % 2, and then once we've test it, we
| | 03:02 | will change it back to 10, just so we
won't have to play the game 10 times in a
| | 03:05 | row to make sure that
the pop-up window shows up.
| | 03:08 | So I'll click to play the game.
| | 03:12 | I'm not going to click on any of the moles.
| | 03:14 | I'm just going to get a gameover.
| | 03:16 | And that first time a call should have
been sent to finishedWithScore and the
| | 03:20 | delegate, and then
timesPlayed should be incremented by 1.
| | 03:24 | And if I play again, when I get
gam over, I should then see the pop-up
| | 03:28 | window, and there it is!
| | 03:32 | If you like Mole It, please
rate it to show your support.
| | 03:36 | If you click Rate, it
won't work in the simulator.
| | 03:39 | You'll actually have to use your device,
because the App Store is not on the
| | 03:43 | simulator, so it won't work.
| | 03:44 | But feel free to test that on your
device if you want to, and then click Cancel,
| | 03:49 | and we'll close the simulator.
| | 03:51 | So now we've successfully set up the
functionality to ask the user to rate the game.
| | 03:56 | I'll just change that to
back to 10, and we're done.
| | 04:00 | So if you want to ask a player to rate
the game, keep track of how many times
| | 04:04 | that they've played the game, and then
every so often you can present an alert
| | 04:10 | menu that will ask the player to rate the game.
| | 04:12 | And if they click Rate, just send
them your link that you get from iTunes
| | 04:16 | Connect, and it will launch that app
in the App Store, and they will be able
| | 04:20 | to rate it.
| | Collapse this transcript |
| Adding support for the Retina display| 00:00 | If you have a device that supports a
high resolution and you're forced to run
| | 00:05 | low-resolution games on it,
they don't look so great.
| | 00:08 | It's always best to support the
retina display, if you can, in your games.
| | 00:13 | To do that, all you need to do is start
out with the art at double resolution.
| | 00:19 | Save versions at the high resolution and
at the low resolutions throughout your
| | 00:24 | project, and it'll be easy to
incorporate retina display features later on.
| | 00:29 | All you have to do is give the
retina display versions an -HD suffix--
| | 00:36 | jetpack-hd.plist for the
HD version of the sprites.
| | 00:41 | So it applies for all the file types.
| | 00:45 | So with that, go into AppDelegate and
change the setting of the director to
| | 00:51 | enable retina display by calling director
ensableRetinaDisplay and passing in Yes.
| | 00:57 | This value you returns Yes if retina
display supported and No if it's not.
| | 01:03 | So if you ever need to check if retina
display is supported, you can check when
| | 01:08 | you apply it and save that value for later on.
| | 01:11 | So now I can test the game in
the simulator and see what I get.
| | 01:15 | You'll notice that it looks exactly the
same in the regular simulator, because
| | 01:20 | the regular simulator runs
the standard iPhone resolution.
| | 01:24 | You can do with a high-res version
in the simulator if you'd like by changing
| | 01:29 | settings in your simulator.
| | 01:31 | So everything looks fine and normal
here on the title screen and if I go to
| | 01:35 | Hardware > Device and change it to iPhone
(Retina), then you can see what it looks
| | 01:41 | like on retina-display device.
| | 01:42 | So we'll just open Molelt.
| | 01:47 | There it is. It fills the whole
screen, and it looks just fine at this
| | 01:53 | higher-resolution display.
| | 01:54 | Now of course it's better if you
actually have a device to test on, but you can
| | 02:00 | just see what it looks like
by watching my screen here.
| | 02:03 | So if you really want to see it on a
device, just plug in a retina display device
| | 02:07 | into your computer and you can test it that way.
| | 02:10 | So remember, to support the retina
display, you need two things, hyphen HD suffix
| | 02:15 | on the files that are high definition,
and then you need to tell the director to
| | 02:20 | enable the retina display.
| | Collapse this transcript |
| Adding support for the iPad| 00:00 | Let's say you want to make your game universal.
| | 00:03 | The first step is to go
into your project settings.
| | 00:06 | You can click on your Target,
and change the device to Universal.
| | 00:10 | Now, as far as cocos2d is concerned,
there really isn't any difference.
| | 00:15 | While there is a different aspect ratio
and different screen size, that's really
| | 00:20 | all you have to worry about.
| | 00:22 | What I usually do is use the HD Sprites
for my iPad version, and I make separate
| | 00:29 | unique backgrounds for the iPad version.
| | 00:31 | Let's take a look at how
to implement some of that.
| | 00:34 | Go to Mainmenu.m, and then we'll
create a variable that checks to see whether
| | 00:40 | the game is running on an iPad.
| | 00:42 | So this will be a Boolean right under
CGSize s. We'll call this isIPAD, and we'll
| | 00:47 | set it equal to, double-brackets, in the
inner brackets, UIDevice, currentDevice,
| | 00:56 | in outer brackets, user InterfaceIdiom,
after the brackets, two equal signs and
| | 01:04 | then UIUserInterfaceIdiomPad.
| | 01:09 | Then we can tell if we're working with an iPad.
| | 01:13 | So for the file name of the sprites,
we'll check to see if it's an iPad and then
| | 01:18 | load the HD version.
| | 01:21 | If you want, you can even do this on one line.
| | 01:24 | After the equal sign, put some
parentheses and then put isIPAD, after the
| | 01:29 | parentheses, a question mark, and space,
and a colon, and then just copy the
| | 01:37 | NSString, stringWithFormat and paste it
in between the question mark and the colon.
| | 01:43 | After the @ symbol in the pasted code,
type -hd. So if it's iPhone, we'll use
| | 01:50 | the normal sprites, and if it's retina,
the system will automatically know to
| | 01:54 | load the HD version.
| | 01:55 | But if it's iPad, we'll tell it to
load the HD versions of the sprites.
| | 02:00 | Then scroll down, and where we set the
title.png for the main screen to load,
| | 02:07 | actually I have a file called
title_IPAD.png in the Assets folder, and that's a
| | 02:13 | full background for the iPad. It looks like this.
| | 02:18 | So back to Mainmenu.m and after the
equals sign in the fileName line of code,
| | 02:23 | we'll check to see if it's an iPad.
| | 02:25 | And if so, we'll load title_IPAD.png,
and a colon after that. And if not, we'll
| | 02:35 | just load regular title.png.
| | 02:37 | So when you test the App, change the
target device to iPad 4.3 simulator, and
| | 02:44 | you can test the app in the simulator and you
should see the iPad version with the iPad art.
| | 02:48 | So here's the iPad simulator and you
see the iPad background and the sprites.
| | 02:57 | And if you wanted to, you can change the
font sizes because they're a little bit small.
| | 03:01 | So you do that in the same way.
| | 03:04 | You check to see if it's an iPad.
| | 03:07 | If so, you put in the custom size for
the font, which we already have set in
| | 03:12 | the F size variable.
| | 03:14 | So if you'd like, you can do that, but
for the rest of the game, you would go
| | 03:18 | through any time when you're loading
some kind of asset, you can load the iPad
| | 03:23 | version if it's an iPad, and the
regular version if it's an iPhone.
| | 03:28 | All you need to do to support the iPad
is change your application settings, and
| | 03:34 | then you can check to see if it's an
iPad with some pre-built Apple code.
| | 03:39 | Then you can hold whether it's an iPad
in a variable and then choose which files
| | 03:44 | to load based on which device the user is using.
| | Collapse this transcript |
|
|
5. Placing Ads in Your GameSetting up iAds for your app| 00:00 | Before you can put iAds in your game, you
need to do some setup in iTunes Connect.
| | 00:05 | So the first thing you want to do is go
to your application in iTunes Connect,
| | 00:10 | and then you can click Set Up iAd Network.
| | 00:13 | If this is the first time you've
used the iAd Network, you may have to
| | 00:16 | look through a contract.
| | 00:18 | You can find that in the
Contract section in iTunes Connect.
| | 00:21 | So if you've done that already,
then you can choose to enable iAds.
| | 00:25 | Now here it's asking if my primary
audience is users under 17 years of age.
| | 00:32 | Now I'm going to click Yes because
this is kind of a kids game and though
| | 00:37 | people may be of all ages that are
playing it, there are going to be a lot of
| | 00:40 | kids, so I'll just click Yes, and
I'll click Enable iAds. Then I can click
| | 00:45 | Save, and Apple asks me if I'm sure
that I have a young audience. I'm going to
| | 00:50 | click Yes and save that.
| | 00:52 | So if your app is geared towards an
older audience, you don't have to target a
| | 00:57 | young audience like I'm doing here.
| | 00:59 | So the next step is to go over into Xcode.
| | 01:03 | Now you want to make sure that
you've imported the iAd framework.
| | 01:08 | You can do that by clicking on your
project and going to Build Phases. So in
| | 01:13 | here, under Link Binary With
Libraries, you can add iAd.framework.
| | 01:19 | So once you have added iAds and
you've brought in the framework into Xcode,
| | 01:24 | you're ready to start writing the
code to add iAds into your game.
| | Collapse this transcript |
| Understanding iAd delegate methods| 00:00 | To add iAd into our game, I created a
helper class called AdViewController.
| | 00:05 | The AdViewController class imports
the iAd framework and adopts the
| | 00:10 | AdBannerViewDelegate protocol.
| | 00:12 | It has an AdBannerView and
some other properties and methods.
| | 00:17 | Let's go to AdViewController.m.
The init method initializes the delegate object,
| | 00:24 | viewDidLoad runs super viewDidLoad,
grabs the EAGLView from the CCDirector and
| | 00:31 | adds it as a sub-view of this view.
| | 00:35 | In our game, the add view is going to act
as the main view rather than the EAGLView.
| | 00:41 | We'll look at how to do that when
we actually write the code, later on.
| | 00:44 | Then I have to check to see if
iAdIsAvailable, which is a simple method that
| | 00:49 | returns if the device is running
the appropriate operating system.
| | 00:54 | Initialize adView set its size and its
frame, set this object as a delegate of
| | 01:01 | the ad view, and then put the
adView as a sub-view of this view.
| | 01:07 | Then there are the delegate methods.
| | 01:09 | There's bannerViewActionShouldBegin,
which says an ad is going to be displayed on
| | 01:14 | the screen in full screen.
| | 01:16 | That means that your application should pause.
| | 01:19 | You also get information about whether
it's going to leave your application.
| | 01:24 | So here's how I handle that.
| | 01:26 | If the app won't leave
then I pause the delegate.
| | 01:30 | bannerViewAction did finish means the
user finished looking at an ad, in which case
| | 01:35 | I resume the delegate.
| | 01:37 | bannerViewDidLoadAd means an ad loaded.
| | 01:41 | If an ad loaded, I run the showBanner
method, provided that the delegate tells me
| | 01:46 | that it's on the game scene.
| | 01:47 | Then there is a method to handle when
the banner fails to load an ad. Then I
| | 01:52 | set adIsLoaded to NO and hide the banner.
| | 01:56 | showBanner sets bannerShouldShow to YES.
| | 01:59 | If the banner is already showing, it
returns. Then using core animation it
| | 02:04 | animates the banner to slide
up at the bottom of the screen.
| | 02:08 | hideBanner does the opposite.
getAdHeight returns the height of the ad, and here's
| | 02:13 | iAdIsAvailable which checks to
see if the iAdClass is accessible.
| | 02:18 | So if you don't have access to the
exercise files, copy down these methods as
| | 02:22 | written and you'll be up to
speed to add this into your project.
| | Collapse this transcript |
| Implementing iAds in your game| 00:00 | Now we'll implement iAds into our game.
| | 00:03 | In AppDelegate.h, add an import
statement to import the AdViewController class.
| | 00:11 | Right below NSString currentSkin,
let's create an AdViewController called adView, capital V.
| | 00:19 | Notice there are a few helper methods in here,
like getAdHeight, hideBanner, and showBanner.
| | 00:24 | Go to AppDelegate.m and at the top
of your code, in applicationDid-
| | 00:31 | FinishLaunching, scroll down and after the
director sets the GLView, give the value to adView.
| | 00:39 | So set it equal to AdViewController,
allocate and init, and then scroll down,
| | 00:50 | and where it says viewController
setView to glView, we're going to set the
| | 00:54 | view to adView.view.
| | 00:57 | Remember, the glView is a
child of AdViewController.
| | 01:02 | Now scroll to the bottom of your code
to find the definitions for getAdHeight,
| | 01:07 | hideBanner, and showBanner.
| | 01:09 | For get AdHeight, return adView getAdHeight.
| | 01:15 | For hideBanner, run adView hideBanner.
| | 01:21 | And for showBanner, run adView showBanner.
| | 01:24 | Now let's go over to Mainmenu.m. We want the
ads to only display while the game is playing.
| | 01:34 | So after you set the delegate, run the
method for the delegate to hideBanner.
| | 01:41 | Then go to Game.m. In here, after
you set the delegate, tell the delegate
| | 01:46 | to show the banner.
| | 01:49 | And then when you set the position of
the pause button, find that line of code
| | 01:54 | and right before the close parenthesis,
| | 01:56 | we're going to add on the
height of the ad. So in brackets,
| | 02:00 | delegate getAdHeight.
| | 02:05 | Now, if you don't have access to the
exercise files, you should be able to
| | 02:08 | test now and see that everything
works fine, but I made one modification to
| | 02:13 | how the game auto-rotates that we'll
have to change real quick to get the
| | 02:17 | iAds working properly.
| | 02:20 | If you're using iAds in landscape,
it's best to have the UIViewController
| | 02:24 | handle autorotation.
| | 02:26 | So in GAME_CONFIG.H, change GAME_AUTOROTATION to
| | 02:30 | kGameAutoRotationUIViewController. And that's it.
| | 02:35 | You should be able to test the app now.
| | 02:37 | And in the simulator, when the game
is playing, you should see an iAd.
| | 02:41 | It's not going to be an actual ad;
| | 02:44 | it's just going to be a sample ad,
because you only see real ads when your game
| | 02:48 | is in the App Store.
| | 02:51 | So, no ads on the Main menu.
| | 02:52 | And if I click Play, and
there is the iAd on the screen.
| | 02:57 | You can see the Pause button is up
a little bit, right above the ad.
| | 03:01 | I can pause and return to the
Main menu, and the ad goes down.
| | 03:05 | So you can use this adViewController
helper class in your own apps, and all
| | 03:10 | you need to do is make calls to
showBanner and hideBanner, and you can show
| | 03:14 | ads within your games.
| | Collapse this transcript |
|
|
6. Adding In-App PurchasesSetting up In-App Purchases (IAPs) in iTunes Connect| 00:00 | Another way you can make money off of
your games is through in-app purchases.
| | 00:05 | In-app purchases are often referred to as IAP.
| | 00:08 | You can add an in-app purchase
through iTunes Connect by going to your
| | 00:12 | application and clicking
Manage in-app purchase.
| | 00:15 | From here you can click Create New to create
a new purchase, and you can choose which type.
| | 00:21 | For the skins, the type is non-consumable,
which means they only have to buy it once.
| | 00:27 | So I will select that, and then I can
choose a Reference Name and a Product ID.
| | 00:32 | The Reference Name will be Mole it Jetpack Skin.
| | 00:38 | Product ID, I am going to paste in
that I copied from the constants.h file.
| | 00:44 | So then you click Add
Language. I will choose English.
| | 00:47 | I will call this Jetpack Skin.
| | 00:52 | Display Description will be Jetpack Skin.
| | 00:54 | I will click Save. For Cleared for Sale,
I have Yes, and I will chose Tier 1 for
| | 01:01 | the Pricing Tier. And you will need
to submit a screenshot in order for the
| | 01:05 | in-app purchase to be reviewed.
| | 01:07 | So I will click Save, and now you will
see my in-app purchase is saved here and note
| | 01:12 | that it says, "Waiting for Screenshot."
| | 01:14 | Now you don't have to submit a
screenshot in order to do testing, but you do
| | 01:19 | before it gets approved and
you can put it in your app.
| | 01:21 | Now let's go over to Xcode.
| | 01:23 | In Xcode make sure you
import store kit into your project.
| | 01:29 | So you can link to that framework, again
under Build Phases and Link Binary with
| | 01:34 | Libraries. So you can add
storekit.framework and once you've done that then
| | 01:39 | you're ready to start working
with in-app purchases in your game.
| | Collapse this transcript |
| Viewing Store Kit delegate methods| 00:00 | To more easily handling in-app
purchases for this game, I created a helper
| | 00:05 | class called Store.
| | 00:07 | In the Store class, I've imported
Foundation, StoreKit, and cocos2d.
| | 00:12 | You will see that it's an
subclass of NSObject and implements
| | 00:15 | SKProductsRequestDelegate and
SKPaymentTransactionObserver, as well as
| | 00:22 | SKRequestDelegate and UIAlertViewDelegate.
| | 00:26 | And there are a few properties and methods.
| | 00:28 | Let's go to Store.m. We will start at the top.
| | 00:33 | The init method adds this object
as an observer of transactions.
| | 00:38 | The makepurchase method begins making
the purchase, and that's done after the
| | 00:46 | initial in-app purchase is created by
calling the requestProductData method.
| | 00:51 | The first thing in that method is
that a check is made to see if the person
| | 00:57 | using the device can make payments.
| | 01:00 | If so, I have a CCLOG
that says, "presenting store."
| | 01:05 | Now, this is not going to work in a
simulator, so you'll need to test this
| | 01:08 | on your own device.
| | 01:09 | And if it's working, you'll see
"presenting store" in the output window.
| | 01:13 | If the person can't make
payments, I show an alert.
| | 01:16 | I also run a method called showAlert,
which shows a simple spinner on the screen
| | 01:22 | and tells the user that we're
waiting for data from Apple.
| | 01:26 | I set the currentpurchase property,
create the ProductsRequest, set the
| | 01:31 | delegate, and start the request.
| | 01:34 | Once Apple has been contacted, you
get a call back in the ProductsRequest,
| | 01:38 | didReceiveResponse method.
| | 01:40 | You can get a lot of information
about the products in this method.
| | 01:45 | First you have an array in response.products.
| | 01:48 | You can grab the first object in the
array or all of them and get information in
| | 01:54 | the way that's presented here.
| | 01:55 | So you can get things like the
price, you can get the description of
| | 02:00 | the product, and all other
things that you can find in the
| | 02:03 | documentation for storeKit.
| | 02:05 | Then I run self makepurchase.
| | 02:08 | When a transaction gets updated, you
get the notification called paymentQueue
| | 02:11 | updatedTransactions.
| | 02:14 | Here you can loop through the
transactions and use a switch case statement to
| | 02:18 | check which transaction occurred.
| | 02:20 | So you can see that if the object was
purchased, the transaction failed, or the
| | 02:25 | transaction state was restored.
| | 02:27 | So for complete transaction, hide the alert,
record the transaction and run a method
| | 02:33 | called provideContent based on
the identifier for the product.
| | 02:37 | And then I run the
finishTransaction method on the SKPaymentQueue.
| | 02:42 | restoreTransaction enables you to
restore a transaction that happened earlier.
| | 02:47 | failedTransaction happens when a
transaction fails, so you can tell the user
| | 02:51 | that the payment did not go through.
| | 02:53 | recordTransaction enables you to record any
information you'd like about a transaction.
| | 02:59 | And in provideContent, I confirm that
the object was purchased with UserDefaults,
| | 03:04 | so we save the value to the device.
And I check to see if the purchase was the
| | 03:09 | IAP_SKIN, and if so, I
setCurrentSkin to SKIN_JETPACK.
| | 03:15 | IAP SKIN is a constant that
holds the string of the productID.
| | 03:21 | When the alertView clicks a
button, then I run self makepurchase.
| | 03:25 | I have hideAlert that
hides the main alert spinner,
| | 03:30 | showAlert that show the main
alert spinner. And that's it.
| | 03:35 | So again, if you don't have access to
the exercise files, just create a class
| | 03:38 | called Store and copy down these
methods as they're written here, and you'll be
| | 03:43 | up to speed to implementing in-
app purchases in your own game.
| | Collapse this transcript |
| Implementing IAPs in your game| 00:00 | To implement in-app purchases,
we'll start in the AppDelegate class.
| | 00:04 | In AppDelegate.h, import Store.h.
Now we'll create a property for store.
| | 00:13 | We'll just call it store, with a
lowercase s, and then we'll create a method in
| | 00:17 | here, and we'll name that method buySkin.
| | 00:22 | Let's go to AppDelegate.m at the very
bottom of the code, right above dealloc.
| | 00:29 | Let's define buySkin.
| | 00:31 | And here I'm simply going to make a
call to the store to request product data.
| | 00:38 | And now we'll initiate the in-app purchase.
| | 00:41 | Now let's initialize the store
inside of applicationDidFinishLaunching.
| | 00:46 | Right under where I set currentSkin,
I'll initialize store by typing store =,
| | 00:53 | and in double brackets, Store alloc init.
| | 00:59 | Now since we allocated memory for the store,
we should release it in the dealloc method.
| | 01:05 | It's right below window release.
| | 01:07 | We'll do the same thing for
store. Lowercase s, release.
| | 01:12 | Then we'll go to Mainmenu.m, scroll
down to the jSkin method where we set the
| | 01:19 | JETPACK skin, and first we'll check
to see if the user bought the skin.
| | 01:24 | So if, in double brackets,
NSUserDefaults, standardUserDefaults, in the outer
| | 01:32 | brackets, boolForKey, and the
key is going to the IAP_SKIN.
| | 01:38 | Then we'll cut and paste delegate
setCurrentSkin:SKIN_JETPACK, and then an
| | 01:46 | else statement, and we'll make a call
to delegate to buy the skin, and that's
| | 01:53 | all there is to it.
| | 01:54 | So we can test this in the simulator,
and while you won't be able to make the
| | 01:57 | in-app purchase in the simulator, you
can see what happens if in-app purchases
| | 02:02 | are disabled on the device.
| | 02:04 | So let's click SKINS, click on the alien,
and then you see a message that says
| | 02:11 | "In-app Purchases Disabled."
| | 02:12 | So you can see what happens when in-
app purchases are disabled on a device.
| | 02:18 | Again, in order to test this, you're
going to need to install this application
| | 02:23 | on your device from Xcode.
| | 02:25 | You'll also need to set up a test user
account through iTunes Connect, and you
| | 02:31 | can use that account information
when testing the in-app purchase.
| | 02:34 | So once you have your store helper
class set up, all you need to do is make a
| | 02:39 | call to its requestProductData method
and you can initiate an in-app purchase.
| | Collapse this transcript |
|
|
7. Adding a Game Center LeaderboardSetting up leaderboards in iTunes Connect| 00:00 | Adding Game Center features can
increase engagement of the users of your game,
| | 00:07 | as well as improve the
amount of gameplay available.
| | 00:10 | So let's take a look at how to add
Game Center leaderboards into your game.
| | 00:15 | In iTunes Connect, go to your
game, and click Manage Game Center.
| | 00:20 | Here you can choose to enable Game Center,
and then you can choose to set up a leaderboard.
| | 00:26 | If you're unfamiliar with the leaderboard,
a leaderboard is a ranking of scores.
| | 00:31 | So each person that plays the
game when connected to Game Center
| | 00:34 | submits their high score to this
leaderboard, and you can see where you rank
| | 00:39 | among other players in the world.
| | 00:41 | So let's quick Add
Leaderboard to create a leaderboard.
| | 00:44 | I'm going to choose Single Leaderboard.
| | 00:47 | And then here I have a Reference Name,
so I'll call this Mole It High Scores.
| | 00:52 | The leaderboard ID is going to be
pasted in from my code, which is the same as
| | 00:58 | my high score key, which is
com.wedgekasegames.moleit.highscore.
| | 01:03 | Score Format Type is going to be Integer,
and Sort Order is going to be High to Low.
| | 01:08 | And if you want information about that,
you can hover over the question mark;
| | 01:11 | it explains which scores get displayed first.
| | 01:15 | So we want high scores at
the top of the leaderboard.
| | 01:19 | Now I'm going to click Add
Language, and I'll choose to add English.
| | 01:23 | I'll call this High Scores--this is what the
user will see when they look at the high scores.
| | 01:29 | For Score Format, I'm going to choose
Integer, and here you can add a suffix,
| | 01:34 | like pt for point or pts for the plural point.
| | 01:38 | That's actually optional.
| | 01:40 | You can also add an optional image.
| | 01:42 | I'm going to skip those right
now, and I'm going to click Save.
| | 01:45 | So now I'll click save one more time to
save the leaderboard, and that's all you
| | 01:50 | need to do in iTunes Connect.
| | 01:52 | So I'll minimize Safari and go into Xcode.
| | 01:56 | Now what you do is import the
Game Kit Framework into your game.
| | 02:01 | Just like any other framework,
you will have to click on your project, go to
| | 02:04 | Build Phases, and click on Link Binary
with Libraries and click the plus button
| | 02:11 | to add the Game Kit framework.
| | 02:13 | So once you've set up your
leaderboard in iTunes Connect and you've added
| | 02:17 | the frameworks into your project,
you're ready to start using Game Center in
| | 02:20 | your games.
| | Collapse this transcript |
| Viewing Game Kit delegate methods| 00:00 | To make using Game Center features easier,
I created a helper class called GKWizard.
| | 00:06 | In GKWizard.h you'll see that I
imported the GameKit framework, and then I have
| | 00:11 | some simple properties and methods.
| | 00:13 | In GKWizard.m, you'll notice that I
imported cocos2d.h and Constants.h. I then
| | 00:20 | set the highScore property
based on UserDefaults value.
| | 00:23 | Then I run a method
called authenticateLocalPLayer.
| | 00:27 | That logs the pLayer into Game Center.
| | 00:29 | Let's scroll down to that method first.
| | 00:33 | The first thing we do is check to
see if Game Center is available.
| | 00:36 | We check to see that by checking the
value returned from isGameCenterAvailable.
| | 00:42 | That method checks to see if the
user has the frameworks and the current
| | 00:47 | operating system installed on their device.
| | 00:50 | Moving on, in authenticateLocalPLayer,
if the pLayer doesn't have Game Center,
| | 00:54 | they see an alert message; and if they
do have Game Center, they get logged in,
| | 00:59 | and then isLoggedinToGC set to YES.
| | 01:02 | I have a method to return the highScore.
| | 01:05 | And then to report a score
to a leaderboard, simply run
| | 01:08 | reportScore forLeaderboard.
| | 01:11 | Here you just pass in a score and
the string with the leaderboard ID, which
| | 01:16 | is the same ID that the
leaderboard has in iTunes Connect.
| | 01:20 | Here we return if Game Center is not available.
| | 01:24 | Then create a score object
called scoreReporter, initing with the
| | 01:28 | Leaderboard category. Set the value.
| | 01:32 | If the saved value of the score is less
than the score passed in, and then run
| | 01:37 | reportScoreWithCompletionHandler.
| | 01:40 | Here we can handle the error if
there is an error reporting the score.
| | 01:44 | So to add Game Center support, you
need to log the player into Game Center,
| | 01:48 | and if you want to report a score to
a leaderboard, then you do it using a
| | 01:51 | GKScore object.
| | Collapse this transcript |
| Implementing a Game Center leaderboard| 00:00 | Now we'll look at implementing the
Game Center features into our game.
| | 00:04 | In AppDelegate.h you'll see that I've
imported GKWizard.h and created a property
| | 00:10 | that's of GKWizard type called wiz.
| | 00:13 | I've also adopted the
GKLeaderboardViewControllerDelegate protocol.
| | 00:17 | This is what we'll use to present the
leaderboard to the players if they ever
| | 00:21 | want to see it from the Main menu.
| | 00:23 | You'll also notice that I added
a method called ShowLeaderboard.
| | 00:27 | Now let's go to AppDelegate.m.
In application didfinishLaunching, I initialized
| | 00:34 | the GKWizard object, and you'll see at
the bottom of the code that I released it.
| | 00:42 | And then in the finishedWithScore method
if the user got a high score, I called the
| | 00:49 | GK Wizard's reportScore
forLeaderboard method and passed in the score and the
| | 00:55 | HighScoreKey for the leaderboard.
| | 00:57 | Remember, that's the constant that is
the same as the user default stored value
| | 01:02 | and the ID for the
leaderboard in iTunes Connect.
| | 01:06 | Let's scroll down to the bottom of the
code and look at how to show a leaderboard.
| | 01:11 | In the ShowLeaderboard method type
GKLeaderboardViewController--we'll call this
| | 01:17 | lb--and in triple brackets,
the innermost bracket will say
| | 01:23 | GKLeaderboardViewController alloc.
| | 01:26 | The next brackets out will say init, and
the third set of brackets is autorelease.
| | 01:31 | On the next line we'll set its
delegate by calling lb.leaderboardDelegate.
| | 01:37 | I'll set it equal to self.
| | 01:39 | Finally, we'll present the
LeaderboardViewController by calling viewController--
| | 01:44 | that's our main viewController--
presentModalViewControllerAnimated.
| | 01:48 | The ModalViewController will
be lb, Animated will be YES.
| | 01:53 | So with self as the delegate of the
leaderboard, once the user sees the
| | 01:58 | leaderboard and clicks the Done
button, then the delegate method
| | 02:01 | leaderboardViewControllerDidFinish
will run. And in that method we tell our
| | 02:05 | viewController to dismiss
the leaderboardViewController.
| | 02:09 | Now we just have to go to the Main menu
and when the user clicks the Game Center
| | 02:13 | button, we want the leaderboard to show.
| | 02:16 | So we go to Mainmenu.m, find the
showLeaderboard method, and in that method, call
| | 02:22 | delegate showLeaderboard.
| | 02:26 | Remember, showLeaderboard is connected
to the Game Center button on the Main
| | 02:29 | menu. So let's test the app in the simulator.
| | 02:33 | Remember, to test Game Center
features, you're going to need a Game
| | 02:36 | Center sandbox account.
| | 02:38 | The easiest way to create your sandbox
account is to go to the Game Center app
| | 02:43 | on your phone, log out of Game Center
if you're already logged in, and then
| | 02:47 | relaunch your main app.
| | 02:50 | So you'll see that I'm already logged
in to Game Center, but if you're not logged
| | 02:54 | in to the Game Center sandbox, you might
be asked to create a new account or to
| | 02:58 | log in using an existing account.
| | 03:00 | The sandbox account is just
for development and testing.
| | 03:04 | It's a whole different set of scores than
what people see when they actually buy the game.
| | 03:09 | So in here I can click Game
Center and I can see the leaderboard.
| | 03:13 | Right now, there aren't any scores.
| | 03:15 | You'll notice the High Scores text field at
the top is saying the name of the leaderboard.
| | 03:20 | I'll just have to rotate the hardware.
| | 03:23 | Now what I want to do is beat my high
score of 2, which shouldn't be too hard,
| | 03:29 | and see that that score gets
submitted to the leaderboard.
| | 03:32 | So I'll play, and what I'm looking for is
to get a high score of 3, and I'm going
| | 03:38 | to lose. After the game is over, I
should be able to go to the main menu,
| | 03:46 | click on Game Center, and see that my
score is updated on the leaderboard.
| | 03:51 | So with Game Center functionality, you
can increase the engagement of users by
| | 03:55 | having them compete with other pLayers
worldwide--and to implement it in your
| | 04:00 | own games, simply used
the GKWizard helper class.
| | Collapse this transcript |
|
|
8. Going Forward and Getting HelpUsing the cocos2d forums| 00:00 | The best place to go for
information about cocos2d is the source;
| | 00:05 | that's cocos2d-iphone.org. On the
main web site, you can go to Documentation
| | 00:12 | and read what's official as to what
works the best in how to optimize your
| | 00:17 | games and from the documentation,
| | 00:19 | you can get the official standpoint
on what works the best in cocos2d.
| | 00:23 | So you can learn how to improve the
performance of your games, whether it
| | 00:27 | be graphics or audio or any
other features that your game has.
| | 00:32 | Also from the main web site,
you can access the forums.
| | 00:36 | The forums are a great place to find any
information to answer questions you may have.
| | 00:41 | Most of the time, if you do a web
search for problem with cocos2d, you will be
| | 00:45 | brought straight into these forums,
| | 00:47 | so I highly recommend looking at them
and checking them first whenever you
| | 00:50 | run into a problem.
| | 00:52 | If you make a good amount of money on
the game from cocos2d, you might want to
| | 00:57 | donate to help the cause.
| | 00:57 | cocos2d is developed by one main
developer, and he puts a lot of its time into
| | 01:04 | building this awesome
platform for developing iOS games.
| | 01:08 | So you can show your appreciation by that.
| | 01:10 | Keep in mind it's not required, but it's just
something that you could always do to help out.
| | 01:14 | cocos2d-iPhone.org is the best and
fastest way to get information about cocos2d.
| | Collapse this transcript |
| Exploring additional iOS game development resources| 00:00 | If you're interested in learning a lot
more about iOS game development using
| | 00:05 | cocos2d, or game development in general,
here are a few resources that you can use.
| | 00:09 | One book that I have is call Learn
iPhone and iPad cocos2d Game Development.
| | 00:14 | This book assumes that you're a
programmer and quickly explains the basics of
| | 00:18 | cocos2d and how to optimize your code.
| | 00:21 | It comes from the perspective
of an iOS application developer,
| | 00:26 | so I thought that book was
very useful in creating apps.
| | 00:29 | Next are something called LevelSVG.
| | 00:31 | LevelSVG is a game that you can
download for free in the App Store that has
| | 00:37 | several different mini-games.
| | 00:39 | It's created by the creator of cocos2d,
and by purchasing it online, you actually
| | 00:44 | get access to all of the source code.
| | 00:46 | It's a great way to get a quick
introduction to how cocos2d works with physics
| | 00:52 | and how to make complex games like
platform games and games that use multiple
| | 00:57 | physics objects together, like cars, and
it's a clean way to see how cocos2d code
| | 01:03 | should be organized and optimized.
| | 01:07 | If you're interested in using other
development tools, you look at the Corona
| | 01:11 | SDK, which you can use to
create cross-platform applications.
| | 01:15 | So you can create one app that
runs on Android, iOS, and Windows 7.
| | 01:23 | Another cross-platform development tool that
works well with 3D games is called Unity 3D.
| | 01:30 | This is an integrated development
environment that allows you to use
| | 01:34 | JavaScript to create games.
| | 01:36 | Since it has a visual interface, it's
easy to lay out elements on the screen.
| | 01:41 | So those are resources that you can use
if you want to build up your power with
| | 01:46 | cocos2d or explore other
options for creating iOS games.
| | Collapse this transcript |
|
|
ConclusionGoodbye| 00:00 | Well, that's it for this course.
| | 00:02 | I hope you had a good time learning
about how to make iOS games using cocos2d.
| | 00:06 | You were able to see how you can create
a game using the basic cocos2d elements
| | 00:11 | like CCScenes, CCLayers, CCSprites.
| | 00:16 | You saw the intricacies of handling
double-taps, single-taps, and simultaneous
| | 00:22 | taps on the screen. And you saw how to
implement extra features into your game
| | 00:27 | like in-app purchases, iAds,
and Game Center features.
| | 00:31 | I hope you had a good time and that
you end up making quality games using the
| | 00:35 | material you learned in this course.
| | 00:37 | If you do, let me know by sending
me a link on Twitter at asktodd.
| | 00:41 | I'll see you next time.
| | Collapse this transcript |
|
|