skippy_winks
skippy_winks

Reputation: 778

Using stuff from other files in Cocos2d?

I am making a game (obviously) and I noticed that my HelloWorldLayer.m file is getting EXTREMELY cramped. I KNOW that there is a way to run methods from other .m files, I just don't know how. For example, I want to have a Character.h and Character.m file. Can I make it so in the HelloWorldLayer init layer, it just uses everything from the Character files instead of having to declare everything in the HelloWorldLayer? I hope my question makes sense, and any help is appreciated. Thanks!

Here is Character.m:

@implementation Character

@synthesize health,velocity;

-(void)dealloc {
    [super dealloc];
}

-(id)initWithTexture:(CCTexture2D *)texture rect:(CGRect)rect
{
    if((self = [super initWithTexture:texture rect:rect]))
    {
        [self scheduleUpdate];
    }
    return self;
}

-(void)update:(ccTime)dt {
    [self setPosition:ccp(self.position.x,self.position.y)];

    self = [CCSprite spriteWithFile:@"nukeboyGreen.gif"];
}

@end

And here's HelloWorldLayer.m (I skimped it down and took out the parts that aren't necessary):

self = [super init];
    if( (self=[super initWithColor:ccc4(255,255,255,255)] )) {

        CGSize winSize = [[CCDirector sharedDirector] winSize];

        character = [Character spriteWithFile:@"nukeboyGreeen.gif"];
        character.position = ccp(winSize.width/2,winSize.height/2);
        character.scale = 0.15;
        [self addChild:character];

Note that I have a Character declared in HelloWorldLayer.h

Upvotes: 1

Views: 196

Answers (1)

Lukman
Lukman

Reputation: 19164

This is where object oriented programming comes to the rescue. OOP encourages you to encapsulate variables and functions that is pertinent to an object in that object itself. In your case, you should put the methods that are specific to Character in the Character class, and only get your HelloWorld to trigger those methods.

Examples:

@interface Character : CCSprite {
   ...
}

- (void)didCollideWith:(Object *)object;

- (void)moveTo:(CGPoint)nextPoint;

- (void)shootArrow:(ckDirection)direction;

- (BOOL)isAlive;

- (int)numberOfLivesRemaining;

...

@end

Then in HelloWorldLayer:

[character moveTo:ccp(100, 200)];
[character shootArrow:kDirectionUp];

if (![character isAlive]) {
   [self showGameOver];
}

Not only that your HelloWorldLayer is less cluttered, you can easily understand what your code does by simply looking at the reasonably named methods.

EDIT:

To answer your question as in the comment about how to designate the sprite image in Character class:

@implementation Character

- (id)init {
   self = [super initWithFile:@"sprite_character.png"];
   if (self) {
       // further customization
   }
   return self;
}

@end

EDIT (after code was added to the question):

First let me point out a few mistake (sorry for the lack of softer word):

  1. You rarely need your sprite to call the [self scheduleUpdate] or [self schedule:SEL]. Normally people implement the update (or tick) method at the CCLayer or CCScene level, where the purpose is to check all the actors (sprites, menus, nested layers etc) for collision/interaction and update their attributes. If you just want to animate movement of a sprite to a specific position, just call runAction method from CCLayer (in the init, update, ccTouchBegan or somewhere). You can read cocos2d-iphone tutorial on Actions by clicking here. So, move the update method and the scheduleUpdate call into your HelloWorldLayer, and then you no longer need to override initWithTexture.

  2. I'm seeing you instantiating a CCSprite in the update method. My above point on the inappropriateness of update method in CCSprite notwithstanding, there is something more important you need to understand when you implement a method: that is you need to decide how and how often your method is going to be used/called. Since the update method is going to be called once per frame (that is 60 times per second), it is simply wrong to unconditionally instantiate an object in that method. You are making the iPhone to allocate (and deallocate) the object with no apparent reason, wasting the processor time/power the device has. You might want to ask where should you instantiate the CCSprite. The answer is in the init method because that method is only called once per object instance. Again, all you need to know is whether a method is going to be called once or multiple times, and decide whether a piece of code should be in there or somewhere else.

  3. In your code for HelloWorldLayer, did you realize that you are calling the super init* methods twice. You don't need to call [super init] since [super initWithColor:ccc4( ... )] is going to call specific init method internally. Although it is not entirely wrong to do so, you are going to break the 'assumption' that init is going to be called once per instance, so you might end up breaking some object integrity unintentionally (and believe me it's going to be hard to debug later)

  4. And finally, care to enlighten me what's the real purpose of the line [self setPosition:ccp(self.position.x,self.position.y)];. You basically set the position of the self object to its current position, so that's like saying "hey you, move your position to your current position" and he'll be like "huh?" :P

Upvotes: 7

Related Questions