views:

449

answers:

2

I am new to Objective-C and iPhone development in general. I am using the Cocos2d-iphone library for a game engine in an attempt to develop a very simple game.

I have been following a few tutorials to get the hang of things and am attempting to put together a very simple "level" where some balls bounce around the screen using the Chipmunk physics engine. Below is the definition and implementation of the file causing the problems. The warning generated during compilation is:

GameScene.m:69: warning: 'GameLayer' may not respond to '-addChild:z:'

GDB also provides the following:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[GameLayer addChild:z:]: unrecognized selector sent to instance 0xf6ff90'

If I comment out this line the program will no longer crash when a GameLayer is called. (Commented the line in question with "<< Apparently . . . error?". It's near the bottom of GameScene.m - The second bit of code in my post.)

// GameScene.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "chipmunk.h"

@interface GameScene : Scene
{
}
@end

@interface GameLayer : Layer
{
    cpSpace *space;
}

-(void) makeBall: (float) x y:(float)y;
-(void) setupGame;

@end

And then the implementation:

// GameScene.m
#import "MenuScene.h"
#import "GameScene.h"

void updateShape(void* ptr, void* unused){
    cpShape* shape = (cpShape*)ptr;
    Sprite* sprite = shape->data;
    if(sprite){
     cpBody* body = shape->body;
     [sprite setPosition:cpv(body->p.x, body->p.y)];
    }
}

@implementation GameScene
- (id) init {
    self = [super init];
    if (self != nil) {
        Sprite * bg = [Sprite spriteWithFile:@"background.png"];
        [bg setPosition:cpv(240, 160)];
        [self add:bg z:0];
        [self add:[GameLayer node] z:1];
    }
    return self;
}
@end

@implementation GameLayer
- (id) init {
    self = [super init];

    if(self != nil) {
     isTouchEnabled = YES;
    }

    //Make it shoot:
    isTouchEnabled = YES;

    //Initialize Chipmunk:
    cpInitChipmunk();

    // Create the chipmunk space
    space = cpSpaceNew();
    cpSpaceResizeStaticHash(space, 400.0f, 40);
    cpSpaceResizeActiveHash(space, 100, 600);

    space->gravity = cpv(0, -400);
    space->elasticIterations = space->iterations;

    // Update Chipmunk
    // Calls the "tick" function below. This function subsequently
    // makes a call to the update function which updates all of the 
    // sprites on the screen.
    [self schedule: @selector(tick:) interval: 1.0f/60.0f];

    // Setup the game (place the player and balls on the screen)
    [self makeBall:100 y:100];

    return self;
}

// Sets up the game, placing the balls on the stage. Also creates the
// flor boundries and player
-(void) setupGame {
}

// Creates a ball and adds it to the desired location on the screen
-(void) makeBall: (float) x y:(float)y {
    Sprite *ball = [[Sprite spriteWithFile:@"start_ball.png"] retain];
    ball.position = cpv(x,y);
    [self addChild:ball z:2]; << Apparently this line is causing the error?
}

-(void)tick: (ccTime)dt {
    cpSpaceStep(space, 1.0f/60.0f);
    //cpSpaceHashEach(space->activeShapes, &updateShape, nil);
}

@end

I've commented the line in the code above that I believe is causing the error. (<< Apparently this line . . .).

I'm sure it's something idiotic, but any help would be appreciated!

Thanks :)

A: 

The compile-time warning is because the @interface part does not have anything called - addChild:z:.

The runtime error is because the @implementation part does not have - addChild:z:.

asveikau
Heh, idiotic indeed. Anyway, I fixed it now. Thanks :)
Louis
checking Cocos2D 0.8.1, the above code should work. The @interface doesn't need to declare addChild:z:, because GameLayer inherits Layer, which inherits CocosNode, and CocosNode implements (and declares) addChild:z:
nash
A: 

I had this problem with Cocos2D 0.8 and developed a workaround which was to declare an array in the layer class which would contain the children objects you want to keep track of.

@interface GameLayer : Layer
{
    cpSpace *space;
    NSMutableArray* children;
}

You can then add children using...

[[self children] addObject:myObject];

It's easy enough to manipulate the contents of that array to whatever you might want to do.

Rob Segal