Cocos2D – Part 2

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:

[c]Scene *scene = [Scene node];[/c]

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:

[c][gameScene addChild:[EnemiesLayer node]];[/c]

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:

[c]#import
#import “Scene.h”

@interface MainScene : Scene {

}

@end[/c]

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:

[c]#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[/c]

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:

[c]- (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];
}[/c]

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:

[c]#import
#import “Layer.h”

@interface PictureLayer : Layer {

}
@end[/c]

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

[c]#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[/c]

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

[c]- (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;
}[/c]

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.

This entry was posted in iPhone, Objective C. Bookmark the permalink.

13 Responses to Cocos2D – Part 2

  1. 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

  2. Phillipe Girouard says:

    @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.

  3. Joe says:

    @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.

  4. David Fan says:

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

  5. egarayblas says:

    I still get this warning guys:

    warning: PictureLayer may not respond to ‘+node’

    Any ideas why?

  6. Julia says:

    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?

  7. Julia says:

    @egarayblas:

    I’m getting the same error.

  8. matrixmode says:

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

  9. carl says:

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

    • keith says:

      Yeah, these tutorials are now somewhat dated. cocos2d changed the whole code structure, now everything is prefaced with CC, but I see you already found that out.

  10. carl says:

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

  11. Nidhi says:

    @carl : The file “cocos2d.h” contains an import call for “CCScene.h” which i think is the Scene.h that is to be included. Did you try that out? or just import “cocos2d.h” and I think it should work.

  12. Icebone1000 says:

    Hello..
    How can you get the touch events for a layer instance that wasnt subclassed?

    myScene : CCScene{

    CCLayer *Layer_1;
    }

    How can I get Layer_1 touches?

Leave a Reply