views:

179

answers:

2

I need to create some compound sprites that will all move and rotate together. Since it's possible to change the position and rotation of an AtlasSpriteManager I've been trying to subclass so I can create a bunch of shortcuts like

CompoundSprite *cSprite = [CompoundSprite spriteManagerWithFile:@"sprites.png"];
[cSprite makeComplexSprite];

internally, it looks a little like this

-(void)makeComplexSprite
{
        AtlasSprite *sp1 = [[AtlasSprite spriteWithRect:CGRectMake(0, 0, 64, 64)       
                             spriteManager:self] retain];
        AtlasSprite *sp2 = [[AtlasSprite spriteWithRect:CGRectMake(0, 0, 64, 64) 
                             spriteManager:self] retain];

    [self addChild:sp1];
    [self addChild:sp2];


    [sp1 setPosition:CGPointMake(0,0)];
    [sp2 setPosition:CGPointMake(64,0)];

}

However, when I run the applications, It crashes with the following exception

Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: '*** -[AtlasSpriteManager makeComplexSprite]: unrecognized selector sent to 
instance 0x107e1c0

Also, if I remove all the code inside 'MakeComplexSprite' and make it do nothing, I also get the same problem.

It's looking like AtlasSpriteManager just doesn't like to be sub classed. Is this the case? If so, why, and how could I work around it?

UPDATE:

I've found a workaround, by creating an NSObject that contains an atlasSpriteManager. It does the trick, but I would still like to subclass AtlasSpriteManager if possible. I appear to be implementing this exaclty as you describe. I'm creating an instance like this

CompoundSprite *cSprite = [CompoundSprite spriteManagerWithFile:@"file.png"]; 
[cSprite makeBox];

which... now I think about it, means that cSprite is still an AtlasSpriteManager since that's what is being returned. hmmmm. Ho do I change that?

+1  A: 

The runtime error you are seeing indicates that your program has tried to send the makeComplexSprite message to an object, but no such method has been defined for that object.

You appear to be sending the makeComplexSprite message to an instance of AtlasSpriteManager instead of an instance of your custom CompoundSprite class. Your example code looks correct, so how are you doing the subclassing? It should look something like this:

CompoundSprite.h:

@interface CompoundSprite : AtlasSpriteManager
{

}
- (void)makeComplexSprite;
@end

CompoundSprite.m:

@interface CompoundSprite
- (void)makeComplexSprite
{
    ...
}
@end

If you do have the subclassing set up properly, make sure you are actually calling makeComplexSprite on an instance of CompoundSprite and not some other object by accident.

Also:

Your code sample has a memory leak. You are creating two autoreleased sprites, then retaining them (which means your class takes ownership of them), and never releasing them. Since the AddChild: method will automatically retain the objects, you can simply lose the retain calls, and everything will be good.

e.James
ah, that's an error on here only. In the code that colon isn't there. i'll update it. My bad.
gargantaun
No worries. I've trimmed that part out of my answer.
e.James
I've found a workaround, by creating an NSObject that contains an atlasSpriteManager. It does the trick, but I would still like to subclass AtlasSpriteManager if possible. I appear to be implementing this exaclty as you describe. I'm creating an instance like thisCompoundSprite *cSprite = [CompoundSprite spriteManagerWithFile:@"file.png"];[cSprite makeBox];which... now I think about it, means that cSprite is still an AtlasSpriteManager since that's what is being returned. hmmmm. Ho do I change that?
gargantaun
grrrrrh, the comments need fixing to allow formatting. I'll add this to the question.
gargantaun
+2  A: 

Implement your own spriteManagerWithFile: or compoundSpriteWithFile: in CompoundSprite, which will return an instance of CompoundSprite.

Edit:

Or, you can do something like

[[ComplexSprite alloc] makeComplexSprite];

But then you need to do the 'spriteManagerWithFile:' part also. Like:

-(id)makeComplexSpriteWithFile:(NSString*)file
{
    if (! (self = [super initWithSpriteManager:..capacity:..]))
       return nil;

    // do your ComplexSprite specific initializing here..

    return self;
}
Ankit