Search code examples
objective-ctouchesbegan

objective-c dynamic type cast while touchesBegan selects a node


I have a couple of sprite nodes on my screen : child1, child2 who both inherit from parent. Parent has 'customAction' method which child1 and child2 both overwrite. And all of them inherit from skspritenode.

Now, in my touchesBegin i use the line

SKSpriteNode * touchedNode = (SKSpriteNode *)[self nodeAtPoint:positionInScene];

But I want to call the child1 version of customAction from child1 if the touched node is of type child1 and child2 version if of child2.

Is there a 'pretty' or 'better' way to do this other than to tag the sprites then using a switch statement to typecast the node to its respective child type?

Thanks!

edit: code

// parent class
@interface animal : SKSpriteNode

-(int)getID;
-(void)yell;

@end

@implementation Animal
{
    int animalID;

    bool clickable;
}

-(id)initAnimalWithIDWithImage:(int)ID :(NSString *)animalType
{
    NSDictionary * returnedAnimal = [animalParser getAnimalByType:animalType];
    NSString *Icon  = [returnedAnimal objectForKey:@"Icon"];

    self = [super initWithImageNamed:Icon];

    animalID = ID;

    return self;
}

-(int)getID
{
    return animalID;
}

-(void)yell
{
    // **todo**
}

@end

// child1
@interface bear : animal

-(void)yell;

@end

@implementation bear

-(id)initBearWithID:(int)ID
{
    return [super initAnimalWithIDWithImage:ID :@"Bear"];
}

-(void)yell
{
    // **todo**
}

@end

// child2
@interface boar: animal

-(void)yell;

@end

// identical to bear

// in the scene

-(id)initGameScene:(CGSize)size :(int)mode
{
    [self initialize:size];
    if(self = [super initWithSize:size])
    {
        bear testBear = [[Bear alloc] initBearWithID:idCount++];
        testBear.position = CGPointMake(300,300);

        [self addChild:testBear];
    }
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch * touch = [touches anyObject];
    CGPoint positionInScene = [touch locationInNode:self];

    // problem solved!
    // this is wrong
    // SKSpriteNode * touchedNode = (SKSpriteNode *)[self nodeAtPoint:positionInScene];

    // this is right
    animal *touchedNode = (animal *)[self nodeAtPoint:positionInScene];

    [touchedNode yell]; 

    // need to something like if touchedNode is a bear do bear yell.. if boar do boar yell
}

Solution

  • Given the code you posted, [touchedNode yell]; is all you need. Dynamic message dispatch takes care of the rest. If it's possible your node won't implement yell, check first with respondsToSelector:.

    To answer the question of how to explicitly identify the thpe, you can use isKindOfClass. That is, if ([touchedNode isKindOfClass:[bear class]]).

    https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/isKindOfClass:

    Also, name your classes with a leading uppercase letter. Lots of things in your app will work better if you follow conventions, like naming classes and accessors regularly.