Content

Bill Gates Touched My Mac Book Pro

Cocos2D – Part 2

Sunday 17 May 2009 - Filed under Objective C + iPhone

I wanted to go a bit more into the base classes of the framework. So far we’ve seen a bit of scenes and sprites. Let’s look at one of the most important base classes, CocosNode.

CocosNode is “the main element. Anything thats gets drawn or contains things that get drawn is a CocosNode.”

So Scene derives from CocosNode, as does Sprite, as do most of the other visual objects you’ll be dealing with. Think of it as DisplayObject in Flash. CocosNode has a static method called “node” which is basically a factory method returning a new CocosNode. Of course, Sprite’s node method will return a new Sprite, and Scene’s method will return a new Scene. We saw that in the last example when we said:

Scene *scene = [Scene node];

Another important class in this structure is Layer. A layer is mainly a way to organize the objects in your scene. So you might have a background layer, an objects layer, a player layer, etc. Layers aren’t mandatory. You can add Sprites and other objects directly to a Scene, but they can certainly help organize things, especially when you start subclassing them. For example you could have an EnemiesLayer class that extends Layer. It has code to create and control enemy characters. You say something like:

[gameScene addChild:[EnemiesLayer node]];

Layers are also UIAccelerometerDelegates and TouchEventDelegates, whereas Scenes are not. So if you need accelerometer or touch data, you might want to create a Layer for that in your scene.

Now in the last example, we created a generic Scene and added a background image to it. Generally, that’s not the way you would do it. Again, a Scene represents a particular state of a game, so it would probably contain its own logic and graphics. Thus, you’d probably subclass Scene and add the background from within. Let’s do that.

Add a new file to the project in the Classes group. Choose NSObject subclass and name it MainScene. In the interface file, import Scene.h and have the class subclass Scene:

#import <foundation/Foundation.h>
#import "Scene.h"

@interface MainScene : Scene {

}

@end

In the implementation file, import Sprite.h and cocos2d.h. Then add an init method, create the background sprite like before, and add it as a child to self:

#import "MainScene.h"
#import "Sprite.h"
#import "cocos2d.h"

@implementation MainScene

- (id) init
{
	self = [super init];
	if (self != nil) {
		Sprite *background = [Sprite spriteWithFile:@"background.png"];
		background.position = ccp(240, 160);
		[self addChild:background];
	}
	return self;
}
@end

Now that MainScene takes care of creating its own background, we can remove that code from the app delegate, and just create a MainScene instead of a generic Scene:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
	window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [window setUserInteractionEnabled:YES];
    [window setMultipleTouchEnabled:YES];

	[[Director sharedDirector] setPixelFormat:kRGBA8];
	[[Director sharedDirector] setDeviceOrientation:CCDeviceOrientationLandscapeLeft];
    [[Director sharedDirector] attachInWindow:window];

    [window makeKeyAndVisible];

	MainScene *mainScene = [MainScene node];
	[[Director sharedDirector] runWithScene:mainScene];
}

Don’t forget to import your new “MainScene.h” file.

Now that you have a custom scene, you could start adding other layers, objects, and logic to it.

Now let’s add a custom Layer. Let’s display some other non-fullscreen graphic in this layer. I’ve added another picture to my project called iphone.png. Create another NSObject subclass named PictureLayer, and have it extend Layer. Here’s the interface:

#import <foundation/Foundation.h>
#import "Layer.h"

@interface PictureLayer : Layer {

}
@end

In the implementation, do the same thing we did with the scene’s background, but add this new picture insted:

#import "PictureLayer.h"
#import "Sprite.h"
#import "cocos2d.h"

@implementation PictureLayer

- (id) init
{
	self = [super init];
	if (self != nil) {
		Sprite *pic = [Sprite spriteWithFile:@"iphone.png"];
		pic.position = ccp(240, 160);
		[self addChild:pic];
	}
	return self;
}

@end

Now, back in MainScene, let’s create add this layer:

- (id) init
{
	self = [super init];
	if (self != nil) {
		Sprite *background = [Sprite spriteWithFile:@"background.png"];
		background.position = ccp(240, 160);
		[self addChild:background];

		PictureLayer *pictureLayer = [PictureLayer node];;
		[self addChild:pictureLayer];
	}
	return self;
}

You wind up with something looking like this:

layer

I know, it’s not high art, but we got the mechanics down, so lets be happy with it!

So I didn’t get into motion yet, but I thought it was important to cover scenes and layers before we went any further. That’s it for today.

2009-05-17  »  keith

Talkback x 11

  1. cocos2d Tutorials - TOC | BIT-101 Blog
    18 May 2009 @ 9:54 am

    [...] 1 Part 2 Part 3 Part 4 More to come. This entry was posted on Sunday, May 17th, 2009 at 9:42 pm and is [...]

  2. Matthew Wallace
    25 May 2009 @ 12:27 pm

    When I add the PictureLayer to the MainScene the application crashes when trying to launch. I don’t get any errors at all. Wondering what I am doing wrong.

    her is my PictureLayer.m code

    #import “PictureLayer.h”
    #import “Sprite.h”
    #import “cocos2d.h”

    @implementation PictureLayer

    - (id) init
    {
    self = [self init];

    if (self != nil)
    {
    Sprite *pic = [Sprite spriteWithFile:@"grossini.png"];
    pic.position = ccp(240, 160);
    [self addChild:pic];
    }

    return self;
    }
    @end

    Here is my MainScene.m code

    #import “MainScene.h”
    #import “Sprite.h”
    #import “cocos2d.h”
    #import “PictureLayer.h”

    @implementation MainScene

    - (id) init
    {
    self = [super init];
    if (self != nil)
    {
    Sprite *background = [Sprite spriteWithFile:@"background.png"];
    background.position = ccp(240, 160);
    [self addChild:background];

    PictureLayer *pictureLayer = [PictureLayer node];;
    [self addChild:pictureLayer];
    }

    return self;
    }
    @end

  3. Phillipe Girouard
    25 May 2009 @ 5:29 pm

    @Matthew Wallace. I believe it could be that double semicolon ‘;’ that you have at the end of the line ” PictureLayer *pictureLayer = [PictureLayer node];; “. Try that and see if it works.

  4. Joe
    26 May 2009 @ 7:14 am

    @Matthew. The double ;; is not causing the crash. It will compile and run fine with two ;;

    The problem is caused by the line: self = [self init].
    Replace the line with: self = [super init] and your program shouldn’t crash anymore.

    @Keith Thanks so much for the great tutorial. Keep up the good work.

  5. David Fan
    28 May 2009 @ 12:37 pm

    @Matthew Wallace. In PictureLayer.m, the line:
    self = [self init];
    to
    self = [super init];

  6. egarayblas
    2 July 2009 @ 11:15 am

    I still get this warning guys:

    warning: PictureLayer may not respond to ‘+node’

    Any ideas why?

  7. Julia
    21 July 2009 @ 8:25 am

    I get a warning: “‘MainScene’ may not respond to “-addChild:”, (methods without a matching signature will be assumed to return ‘id’ and accept “…” as arguments).”

    Why is this happening?

  8. Julia
    22 July 2009 @ 9:06 am

    @egarayblas:

    I’m getting the same error.

  9. matrixmode
    28 July 2009 @ 8:12 pm

    reguarding the add child problem, you probably derived the PictureLayer from nsobject, but should have changed it to Layer. (in PictureLayer.h)

  10. carl
    25 February 2010 @ 7:19 pm

    trying to get this to work with cocos2d .99 which doesn’t seam to contain scene.h

  11. carl
    25 February 2010 @ 7:24 pm

    well ‘doh CCScene CCDirector CCSprite, ok, but I still have linking problems out of the box, hmmmmm

Share your thoughts

Re: Cocos2D – Part 2







Tags you can use (optional):
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>