BrainLikeADullPencil
BrainLikeADullPencil

Reputation: 11653

unable to getChildByTag

I'm following along with the Lynda.com iOS tutorial for game development which uses cocos2d (version 2). The instructor uses the following code to make the sprite image increase in size upon a touch event. The log statement in the code below is working (i.e. touch events are enabled) but the image is not getting larger when I click on the simulator. It turns out that mole in this line is nil

CCSprite *mole =  (CCSprite *)[self getChildByTag:1];

Here's the whole method

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView: [touch view]];
    location = [[CCDirector sharedDirector] convertToGL: location ];
    CCLOG(@"touch happened at x: %0.2f y: %0.2f",location.x, location.y );
    CCSprite *mole =  (CCSprite *)[self getChildByTag:1];

    if (CGRectContainsPoint([mole boundingBox], location)) {
        [mole runAction:[CCSequence actions:
                         [CCScaleTo actionWithDuration:.25 scale:1.1],
                         [CCScaleTo actionWithDuration:.25 scale:1.0],
                         nil]];
    }
}

The mole is appearing on the screen with this init method below. I'm assuming the line from above CCSprite *mole = (CCSprite *)[self getChildByTag:1]; is supposed to get a reference to the mole as a child but it's not obviously working.

-(id) init
{
    // always call "super" init
    // Apple recommends to re-assign "self" with the "super" return value
    if( (self=[super init])) {
        self.isTouchEnabled = YES;
        CGSize s = [[CCDirector sharedDirector] winSize];
        CCSprite *mole = [CCSprite spriteWithFile:@"mole.png"];
        mole.position = ccp(s.width/2,s.height/2);
        [self addChild:mole];
        mole.tag = 1;

        CCSprite *bg = [CCSprite spriteWithFile:@"bg.png"];
        bg.anchorPoint = ccp(0,0);
        [self addChild:bg z:-1];
    }
    return self;
}

Can you tell from the above code why mole here is nil?

 CCSprite *mole =  (CCSprite *)[self getChildByTag:1];

Update

HelloWorldLayer.h

#import <GameKit/GameKit.h>

// When you import this file, you import all the cocos2d classes
#import "cocos2d.h"

// HelloWorldLayer
@interface HelloWorldLayer : CCLayer <GKAchievementViewControllerDelegate, GKLeaderboardViewControllerDelegate>
{
}

// returns a CCScene that contains the HelloWorldLayer as the only child
+(CCScene *) scene;

@end

HelloWorldLayer.m

// Import the interfaces
#import "HelloWorldLayer.h"

// Needed to obtain the Navigation Controller
#import "AppDelegate.h"

#pragma mark - HelloWorldLayer

// HelloWorldLayer implementation
@implementation HelloWorldLayer

// Helper class method that creates a Scene with the HelloWorldLayer as the only child.
+(CCScene *) scene
{
    // 'scene' is an autorelease object.
    CCScene *scene = [CCScene node];

    // 'layer' is an autorelease object.
    HelloWorldLayer *layer = [HelloWorldLayer node];

    // add layer as a child to scene
    [scene addChild: layer];

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
-(id) init
{
    // always call "super" init
    // Apple recommends to re-assign "self" with the "super's" return value
    if( (self=[super init]) ) {

        self.isTouchEnabled = YES;

        // create and initialize a Label
//      CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];
//
//      // ask director for the window size
//      CGSize size = [[CCDirector sharedDirector] winSize];
//
//      // position the label on the center of the screen
//      label.position =  ccp( size.width /2 , size.height/2 );
//      
//      // add the label as a child to this Layer
//      [self addChild: label];

        CGSize s = [[CCDirector sharedDirector] winSize];
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"moles.plist"];
        CCSprite *mole = [CCSprite spriteWithSpriteFrameName:@"a0010.png"];
//      CCSprite *mole = [CCSprite spriteWithFile:@"mole.png"];
        mole.position = ccp(s.width/2,s.height/2);
        mole.scale = .25;
        //between 0 255
//        mole.opacity = 100;
        NSMutableArray *frames = [[NSMutableArray alloc] init];
        for (int i = 1; i <= 10; i++) {
            NSString *frameName = [NSString stringWithFormat:@"a%04i.png",i];
            [frames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:frameName]];
        }
        CCAnimation *a = [CCAnimation animationWithFrames:frames delay:1.0f/24.0f];
        [mole runAction:[CCAnimate actionWithAnimation:a restoreOriginalFrame:NO]];
        [self addChild: mole];


        CCSprite *bg = [CCSprite spriteWithFile:@"bg.png"];
        //supposed to fill whole screen but not

        //got next three lines from SO
    //stackoverflow.com/questions/12383228/how-to-set-background-image-for-the-entire-scene-in-cocos2d-xcode
        CGSize imageSize = bg.contentSize;
        bg.scaleX = s.width/ imageSize.width;
        bg.scaleY = s.height/ imageSize.height;

        bg.anchorPoint = ccp(0,0);
        [self addChild:bg z:-1];
        //
        // Leaderboards and Achievements
        // *

//      // Default font size will be 28 points.
//      [CCMenuItemFont setFontSize:28];
//      
//      // to avoid a retain-cycle with the menuitem and blocks
//      __block id copy_self = self;
//      
//      // Achievement Menu Item using blocks
//      CCMenuItem *itemAchievement = [CCMenuItemFont itemWithString:@"Achievements" block:^(id sender) {
//          
//          
//          GKAchievementViewController *achivementViewController = [[GKAchievementViewController alloc] init];
//          achivementViewController.achievementDelegate = copy_self;
//          
//          AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
//          
//          [[app navController] presentModalViewController:achivementViewController animated:YES];
//          
//          [achivementViewController release];
//      }];
//      
//      // Leaderboard Menu Item using blocks
//      CCMenuItem *itemLeaderboard = [CCMenuItemFont itemWithString:@"Leaderboard" block:^(id sender) {
//          
//          
//          GKLeaderboardViewController *leaderboardViewController = [[GKLeaderboardViewController alloc] init];
//          leaderboardViewController.leaderboardDelegate = copy_self;
//          
//          AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
//          
//          [[app navController] presentModalViewController:leaderboardViewController animated:YES];
//          
//          [leaderboardViewController release];
//      }];
//
//      
//      CCMenu *menu = [CCMenu menuWithItems:itemAchievement, itemLeaderboard, nil];
//      
//      [menu alignItemsHorizontallyWithPadding:20];
//      [menu setPosition:ccp( size.width/2, size.height/2 - 50)];
//      
//      // Add the menu to the layer
//      [self addChild:menu];

    }
    return self;
}

//- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
//{
//    acceleration.x
//}

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView: [touch view]];
    location = [[CCDirector sharedDirector] convertToGL: location ];
    CCLOG(@"touch happened at x: %0.2f y: %0.2f",location.x, location.y );
    CCSprite *mole =  (CCSprite *)[self getChildByTag:1 ];
    NSLog(@"mole %@", mole);
//    if (CGRectContainsPoint([mole boundingBox], location))
//    {
//        [mole runAction: [CCScaleBy actionWithDuration:.25 scale:1.1]];
//        
//    }
    if (CGRectContainsPoint([mole boundingBox], location)) {
        [mole runAction:[CCSequence actions:
                         [CCScaleTo actionWithDuration:.25 scale:1.1],
                         [CCScaleTo actionWithDuration:.25 scale:1.0],
                         nil]];
    }
}

// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
    // in case you have something to dealloc, do it in this method
    // in this particular example nothing needs to be released.
    // cocos2d will automatically release all the children (Label)

    // don't forget to call "super dealloc"
    [super dealloc];
}

#pragma mark GameKit delegate

-(void) achievementViewControllerDidFinish:(GKAchievementViewController *)viewController
{
    AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
    [[app navController] dismissModalViewControllerAnimated:YES];
}

-(void) leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
    AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
    [[app navController] dismissModalViewControllerAnimated:YES];
}
@end

Upvotes: 2

Views: 253

Answers (3)

jd.
jd.

Reputation: 84

Do what KARTHIK RA says.

Alternatively, you can subclass CCSprite and add the touch detection and handlers within the subclass. I do this when I have several touchable sprites because:

  • It eliminates the needs to continually check all the children in a scene/layer on touch
  • You can create the action ahead of time within your sprite class and just run it when the touch is detected
  • It separates the action logic from the scene
  • When touch is detected, you know for a fact which object is touched

Good luck with cocos2d. It's a great engine. If you do migrate to version 3, keep in mind that "tag" is no longer a property of CCNode. It has been replaced by "name" which is actually a string type. Tag was an int type.

Upvotes: 0

KARTHIK  RA
KARTHIK RA

Reputation: 469

  // set the tag value mole sprite in init method (HelloWorldLayer.m).

   CCSprite *mole = [CCSprite spriteWithSpriteFrameName:@"a0010.png"];
    //      CCSprite *mole = [CCSprite spriteWithFile:@"mole.png"];
    mole.position = ccp(s.width/2,s.height/2);
    mole.scale = .25;
    mole.tag=1;

Upvotes: 4

KARTHIK  RA
KARTHIK RA

Reputation: 469

to check null value:

    if(mole!=NULL) //check null value
   {
      if (CGRectContainsPoint([mole boundingBox], location)) 
        {
          [mole stopAllActions];
          [mole runAction:[CCSequence actions:
                     [CCScaleTo actionWithDuration:.25 scale:1.1],
                     [CCScaleTo actionWithDuration:.25 scale:1.0],
                     nil]];
         }

   }

Upvotes: 0

Related Questions