Dieses Dokuwiki verwendet ein von Anymorphic Webdesign erstelltes Thema.

Lesson Goals

When you're through with this lesson, you will be able to create a new cocos2d project, add some sprites, and get them to move around either autonomously or in response to touch events.

Please be sure you understand Lesson 1. Install & Test as well as the basic concepts before proceeding.

Initial Setup

As described in Lesson 1, you should start by creating a new project with the “cocos2d-(version) Application” template. Call it “Lesson1” and save it somewhere handy, then run it to make sure it displays the “Hello World” you expect.

You will probably have noticed by now that it launches with a cocos2d splash screen, and when you quit the demo by pressing the simulated Home button, you can see that it has a cocos2d icon as well. Those come from specially-named images in the “Resources” folder in your project (and on disk). Find them now, and check them out, since you will eventually want to replace them with your own images – and because this is also where you'll add images for backgrounds and sprites.

(If you want to replace the splash and/or icon now, simply replace the images on disk with new ones of the same size, naming them exactly “Default.png” and “Icon.png” – that's all there is to it.)

Let's add an additional image at this point, for use as a sprite. Save the image at right to the “Resources” folder of your project on disk, naming it “seeker.png”. Now switch back to Xcode, and look in the Resources folder there. You'll find that seeker.png isn't there: just adding a file on disk doesn't automatically add it to the project. Grab it in the Finder and drag it into the Resources folder in your Xcode project. A dialog will appear with some options: you can leave them all at the defaults, and click “Add”. You should now have seeker.png in the Resources folder in your project.

We'll need two sprites for this lesson, but for the sake of brevity, let's just use the Icon.png image already included in the project as our second sprite.

Creating the Sprites

Now twist open the Classes folder. You should have four files here, representing two classes: HelloWorldScene, and Lesson1AppDelegate (In the new versions of the template, use HelloWorldLayer and AppDelegate instead). We're going to do all the coding for this lesson in HelloWorldScene.m, so select that file.

The first thing we're going to need is some way to refer to our sprites. A local variable would do if we only needed to refer to them in one method, but that's rarely the case; we will be moving some sprites around in response to touch events, moving others on every frame according to some logic, and so on. All that necessitates referring to a sprite from multiple methods.

There are several ways to do that. Most of the demo/test code works by assigning a numeric “tag” to each sprite when it is added to the layer, and then later, looking that sprite up using the getChildByTag method. That's a safe approach, but a lot of extra work, and could be a performance issue in big games with hundreds of sprites.

So we're going to use a simpler method, which will be safe as long as you don't have more than one instance of the scene running at once (which would be quite unusual). We're simply going to declare file-scope variables to point to the sprites. So at the top of the file, just after the ”#import” line, add these two lines:

CCSprite *seeker1;
CCSprite *cocosGuy;

That gets us two CCSprite pointers, which can refer to two sprite objects. Initially they don't refer to anything, but we'll fix that in the “init” method next.

Find the method called ”-(id) init”. This method is automatically called when the scene (actually, the main layer within the scene) is being created. The confusing “if” line within that, as well as the “return self” at the end, are boilerplate; just leave them alone. All the stuff that changes from scene to scene goes within the “if” block.

Delete the current contents of that “if” block – those lines created the “Hello World” label, which we no longer need. Replace them with these:

        // create and initialize our seeker sprite, and add it to this layer
        seeker1 = [CCSprite spriteWithFile: @"seeker.png"];
        seeker1.position = ccp( 50, 100 );
        [self addChild:seeker1];
 
        // do the same for our cocos2d guy, reusing the app icon as its image
        cocosGuy = [CCSprite spriteWithFile: @"Icon.png"];
        cocosGuy.position = ccp( 200, 300 );
        [self addChild:cocosGuy];

We added three lines for each sprite. The first line calls spriteWithFile, to create a new CCSprite object with an image that's part of the project.

The next line sets the position of the center of the sprite on the screen, using the “ccp” (cocos2d point) macro to create a 2D point (technically, a CGPoint structure) from X and Y coordinates. Note that in cocos2d, X coordinates start at the left side of the screen and increase to the right; Y coordinates start at the bottom of the screen and increase upwards.

Finally, the third line for each sprite calls “addChild” to add the newly created sprite to the layer.

Save (cmd-S) and Run (cmd-R) your code. The result should look like this:

lesson2-screenshot1.jpg

Making Things Move

Now that you know how to make sprites appear on the screen, you'll want to make them move around. There are two basic approaches to this:

  1. Use an Action to tell the sprite to automatically move to a target position over a certain amount of time; or
  2. Move the sprite yourself in a method that gets called periodically during the game.

Let's take the second approach first. Go back to your “init” method in HelloWorldScene.m. The code within the “if” block here creates your sprites. We're going to add one more step to that initialization: scheduling a periodic callback. Put this code within the “if” block, right after the ”[self addChild: cocosGuy];” line:

        // schedule a repeating callback on every frame
        [self schedule:@selector(nextFrame:)];

This calls the “schedule” method on self (the HelloWorld CCLayer), and passes the address of a method called “nextFrame” that takes one argument. No such method exists yet, but that's OK, we're about to create it. Find a blank line that's not within any method, for example, after the end of the init method but before the dealloc method. Insert this code:

- (void) nextFrame:(ccTime)dt {
    seeker1.position = ccp( seeker1.position.x + 100*dt, seeker1.position.y );
    if (seeker1.position.x > 480+32) {
        seeker1.position = ccp( -32, seeker1.position.y );
    }
}

The net effect of this work is that on every frame of the animation, the cocos2d library will call your “nextFrame” event and pass in the time (in seconds) since the last frame. This is your opportunity to do all sorts of handy things: move sprites around, check for collisions, update a physics model, spawn new enemies, remove sprites that are no longer needed, etc.

In our case, all we need to do here is move the “seeker1” sprite. To move a sprite, you just assign a new value to its “position” property. (You'll probably be tempted to assign to just the .x or .y parts of the position, but that doesn't work; you have to assign a whole new point.)

We're incrementing the x part of the sprite position by 100*dt – which means that in one second, the sprite will have move 100 pixels. This technique of multiplying the desired speed (in pixels/second) by dt to get the amount to move a sprite is a great one, because it means the motion will be at a constant speed, even if the frame rate varies a bit.

Then we check to see whether the sprite has gone off the screen. We're assuming here an iPhone in landscape mode, which is 480 pixels wide; to make your code more general you could call [ [CCDirector sharedDirector] winSize] to get the actual size of the screen. But 480 will do for now; and we add 32 because that's half the width of this sprite – so when the center is beyond 480+32, the whole sprite is off screen to the right. When that happens, we reset the x position to -32, which places it fully off screen to the left.

Responding to Touch

Handling Events is a little different from scheduling a callback. Events include things like touches on the screen and accelerometer readings. There are already specific methods defined for these – and in the case of touch events, there are two different approaches: “standard” or “targeted”. Please see Touch Delegates for a deeper discussion.

For the sake of this lesson, we'll use the targeted delegate. This requires several changes to the code. First, at the top of the file, just after importing “HelloWorldScene.h”, add:

#import "CCTouchDispatcher.h"

Now find a space for a new method, perhaps after the end of the “init” method. We need to tell the CCLayer code that we want the “targeted” set of touch events rather than the “standard” set:

-(void) registerWithTouchDispatcher
{
	[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}

Next, find that “init” method again, and just before the end of the big “if” block, insert this line to register for touch events:

    self.isTouchEnabled = YES;

Now find a space for a new method, perhaps after the end of the nextFrame method you wrote above. Because we're using the “targeted” set of touch events, we have to implement at least the ccTouchBegan method. Return YES here to tell the touch dispatcher that you want to claim this touch:

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    return YES;
}

That will result in the other touch methods being called on the same touch. Let's add some code to move our second sprite to wherever the touch ends:

- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
	CGPoint location = [self convertTouchToNodeSpace: touch];
 
	[cocosGuy stopAllActions];
	[cocosGuy runAction: [CCMoveTo actionWithDuration:1 position:location]];    
}

convertTouchToNodeSpace is doing several things for us here:

  1. First it gets the location of the touch in its view.
  2. Then it asks the CCDirector to convert this to GL coordinates, i.e. the same coordinate system we use for drawing. (This converts between portrait and landscape coordinates, for example.)
  3. Finally it converts those GL coordinates into node-space, which for our CCLayer, makes no difference.

Then we do the following:

  1. Next we stop any previous Actions our cocosGuy sprite might be doing.
  2. Finally, we run a new action, which moves cocosGuy to the touch location over 1 second.

Note that we don't need any code in our nextFrame event to make this sprite move, because we're using actions instead.

Run the app and try it out – you should find that when you take your finger off the screen (or mouse button off the simulator!), the cocos2d icon scoots right over to that position, while the seeker bot continues to scoot across the screen the whole time.

When you're ready, head on to Lesson 3. Menus and Scenes.

prog_guide/lesson_2._your_first_game.txt · Last modified: 2012/12/20 23:17 by golergka
Trace: lesson_2._your_first_game
Dieses Dokuwiki verwendet ein von Anymorphic Webdesign erstelltes Thema.
CC Attribution-Noncommercial-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0