Search code examples
objective-cxcodecocos2d-iphoneinstance-variablesundeclared-identifier

ObjC: Can't access ivar of custom class from outside


I'm attempting to make a basic game in cocos2d, and I've gotten to the point where I'm attempting to scroll the background depending on the hero sprite's position. The hero's created alongside the controls in a class called GameplayLayer, and all works fine for non-scrolling backgrounds.

The book I'm following has given me some sample code to get the scrolling working based on when my character passes the half-way point, which seems perfect, but it's not executing, I believe this is because it's creating another instance of my Hero class, and there's no link between that instance, and the one that's displayed onscreen.

I'm assuming that I can fix this by making the working instance of my hero accessible from within the background scrolling class (which is called YrrasCoastBackgroundLayer), but I'm having a brain-block and can't get it to see it. I've tried a @property, but Xcode just won't see it in the other class.

Here's the .h file from the GameplayLayer class, where the hero is created / hooked up to controls, etc.:

#import "CCLayer.h"
#import "cocos2d.h"
#import "CommonProtocols.h"
#import "SneakyJoystick.h"
#import "SneakyButton.h"
#import "SneakyJoystickSkinnedBase.h"
#import "SneakyButtonSkinnedBase.h"
#import "HeroMale.h"
#import "GameCharacter.h"

@interface GameplayLayer : CCLayer <GameplayLayerDelegate> {
    CCSprite *playerSprite;
    SneakyJoystick *playerJoystick;
    SneakyButton *jumpButton;  
    CCSpriteBatchNode *sceneSpriteBatchNode;
    HeroMale *heroMale;
}

@property (nonatomic, readonly) SneakyJoystick *playerJoystick;
@property (nonatomic, readonly) SneakyButton *jumpButton;
@property (nonatomic, assign) HeroMale *heroMale;

@end

The YrrasCoastBackgroundLayer.h file definitely imports GameplayLayer.h, and here's the contents of the method in YrrasCoastBackgroundLayer.m file which I want to be able to access that *heroMale ivar:

- (void) adjustLayer {
    float heroXPosition = heroMale.position.x;
    CGSize screenSize = [[CCDirector sharedDirector] winSize];
    float halfOfTheScreen = screenSize.width / 2.0f;
    CGSize levelSize = [[GameManager sharedGameManager] getDimensionsOfCurrentScene];

    if ((heroXPosition > halfOfTheScreen) && (heroXPosition < (levelSize.width - halfOfTheScreen))) {
        float newXPosition = halfOfTheScreen - heroXPosition;
        [self setPosition:ccp(newXPosition, self.position.y)];
    }
}

I'm getting an Xcode error on the float heroXPosition = heroMale.position.x line, stating that heroMale is an undeclared identifier. How can I make it usable here, and will that even solve the problem?

UPDATE:

Here's the .h file for YrrasCoastBackgroundLayer:

#import "CCLayer.h"
#import "cocos2d.h"
#import "HeroMale.h"
#import "GameplayLayer.h"

@interface YrrasCoastBackgroundLayer : CCLayer {
    // Web Tutorial
    CCParallaxNode *backgroundNode;
    CCSprite *backgroundImage;

    // Book Tutorial
    CCSpriteBatchNode *sceneSpriteBatchNode;
    CCParallaxNode *parallaxNode;
}

@property (nonatomic, assign) GameplayLayer *gameplayLayer;

@end

And here's the YrrasCoastBackgroundLayer.m:

#import "YrrasCoastBackgroundLayer.h"

@implementation YrrasCoastBackgroundLayer

@synthesize gameplayLayer;

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

if (self != nil) {

    // Web Tutorial
    backgroundNode = [CCParallaxNode node];
    [self addChild:backgroundNode z: -1];

    backgroundImage = [CCSprite spriteWithFile:@"yrras-coast-ipad-hd.png"];

    CGPoint dustSpeed = ccp(0.1, 0.1);

    [backgroundNode addChild:backgroundImage z:0 parallaxRatio:dustSpeed positionOffset:ccp(1024, [[CCDirector sharedDirector]winSize].height / 2)];

    self.gameplayLayer = gameplayLayer;

    [self scheduleUpdate];

    }
    return self;
}

- (void)update:(ccTime)deltaTime {

    // Web Tutorial
    // CGPoint backgroundScrollVel = ccp(-1000, 0);
    // backgroundNode.position = ccpAdd(backgroundNode.position, ccpMult(backgroundScrollVel, deltaTime));

    CCArray *listOfGameObjects = [sceneSpriteBatchNode children];
    for (GameCharacter *tempChar in listOfGameObjects) {
        [tempChar updateStateWithDeltaTime:deltaTime andListOfGameObjects:listOfGameObjects];
    }
    [self adjustLayer];

}

// Book Tutorial
- (void) adjustLayer {
    float heroXPosition = gameplayLayer.heroMale.position.x;
    CCLOG(@"heroXPosition is %f", gameplayLayer.heroMale.position.x);
    CGSize screenSize = [[CCDirector sharedDirector] winSize];
    float halfOfTheScreen = screenSize.width / 2.0f;
    CGSize levelSize = [[GameManager sharedGameManager] getDimensionsOfCurrentScene];
    if ((heroXPosition > halfOfTheScreen) && (heroXPosition < (levelSize.width - halfOfTheScreen))) {
        float newXPosition = halfOfTheScreen - heroXPosition;
        [self setPosition:ccp(newXPosition, self.position.y)];
    }
}

@end

Solution

  • You need an instance of your GameplayLayer to be passed to the YrrasCoastBackgroundLayer layer.

    You can declare an assignable property in YrrasCoastBackgroundLayer :

    @property (nonatomic, assign) GameplayLayer gamplayLayer;
    

    and when you initialize your YrrasCoastBackgroundLayer pass the instance of the game play layer and in your adjustLayer method do :

    float heroXPosition = gameplayLayer.heroMale.position.x;
    

    EDIT :

    assuming this is how you create your scene :

      MyScene *scene = [MyScene scene];
      gameplayLayer = [[GameplayLayer alloc] init];
      bgLayer = [[YrrasCoastBackgroundLayer alloc] init];
      bgLayer.gameplayLayer = gameplayLayer; // This is where you assign the gameplay Layer to the background layer;
    
      [scene addChild:bgLayer];
      [scene addChild:gameplayLayer];
    
      // Release both layers if you dont need them anymore here (scene addChild retains them when they are added)      
      [gameplayLayer release];
      [bgLayer release];