ObjC: невозможно получить доступ к ivar пользовательского класса извне

Я пытаюсь сделать базовую игру в cocos2d, и я дошел до того, что пытаюсь прокрутить фон в зависимости от положения спрайта героя. Герой создается вместе с элементами управления в классе GameplayLayer, и все это прекрасно работает для фонов без прокрутки.

Книга, за которой я следую, дала мне пример кода, чтобы прокрутка работала на основе того, когда мой персонаж проходит половину пути, что кажется идеальным, но не выполняется, я полагаю, это потому, что он создает другой экземпляр моего героя class, и нет никакой связи между этим экземпляром и тем, который отображается на экране.

Я предполагаю, что смогу исправить это, сделав рабочий экземпляр моего героя доступным из класса фоновой прокрутки (который называется YrrasCoastBackgroundLayer), но у меня блокировка мозга, и я не могу заставить его это увидеть. Я пробовал @property, но Xcode просто не увидит его в другом классе.

Вот файл .h из класса GameplayLayer, где герой создается/подключается к элементам управления и т.д.:

#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

Файл YrrasCoastBackgroundLayer.h определенно импортирует GameplayLayer.h, и вот содержимое метода в файле YrrasCoastBackgroundLayer.m, к которому я хочу получить доступ к этому *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)];
    }
}

Я получаю ошибку Xcode в строке float heroXPosition = heroMale.position.x, в которой говорится, что heroMale является необъявленным идентификатором. Как я могу сделать его пригодным для использования здесь, и решит ли это проблему?

ОБНОВИТЬ:

Вот файл .h для 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

А вот 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

comment
Пожалуйста, добавьте код для вашего класса HeroMale.. И его атрибуты...   -  person Nikhil Aneja    schedule 14.05.2012


Ответы (2)


Вам нужен экземпляр вашего GameplayLayer для передачи на слой YrrasCoastBackgroundLayer.

Вы можете объявить назначаемое свойство в YrrasCoastBackgroundLayer :

@property (nonatomic, assign) GameplayLayer gamplayLayer;

и когда вы инициализируете свой YrrasCoastBackgroundLayer, передайте экземпляр игрового слоя и в своем методе adjustLayer выполните:

float heroXPosition = gameplayLayer.heroMale.position.x;

ИЗМЕНИТЬ:

предполагая, что именно так вы создаете свою сцену:

  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];
person giorashc    schedule 14.05.2012
comment
Итак, это построено, но похоже, что это не решило мою проблему, код прокрутки все еще не выполняется, когда он должен быть. - person Luke; 14.05.2012
comment
На самом деле, похоже, что этот код никогда не активируется: [self setPosition:ccp(newXPosition, self.position.y)]; } - person Luke; 14.05.2012
comment
Достигается ли когда-нибудь сам метод? (попробуйте отладить) - person giorashc; 14.05.2012
comment
Да, метод вызывается, но оператор if внутри него никогда не выполняется, потому что heroXPosition всегда равен нулю, когда он вызывается в этом классе — данные не передаются. - person Luke; 14.05.2012
comment
покажи мне, как ты передал объект игрового слоя фоновому слою - person giorashc; 14.05.2012
comment
Именно так, как вы сказали выше. В файле .h фонового слоя есть @property (nonatomic, assign) GameplayLayer *gameplayLayer;, тогда это @synthesized в файле .m. Затем я пытаюсь вызвать его с помощью `float heroXPosition = gameLayer.heroMale.position.x; ` - person Luke; 14.05.2012
comment
что вам нужно сделать, это создать свой игровой слой (давайте назовем его playerLayer), а затем, когда вы создаете свой фоновый слой (давайте назовем его bgLayer), вы должны сделать: bgLayer.gameplayLayer = gameLayer; - person giorashc; 14.05.2012
comment
Это не имело никакого значения. Он не знает, что геймплейный слой после знака равенства принадлежит внешнему классу. Он присваивает его себе, если что, конечно? - person Luke; 14.05.2012
comment
Мне нужно будет увидеть ваш код инициализации. Можете ли вы отредактировать свой пост и заменить некоторые из них на него? Спасибо - person giorashc; 14.05.2012
comment
Есть файлы .h и .m для фонового слоя, они вам нужны? - person Luke; 14.05.2012
comment
Но где вы назначаете экземпляр gameLayer указателю gameLayer фонового слоя? (Просто объявить и синтезировать свойство недостаточно) - person giorashc; 14.05.2012
comment
Это в файле .m — self.gameplayLayer = gameplayLayer; — не так ли? - person Luke; 14.05.2012
comment
Вы должны передать своему методу init настоящий экземпляр gameplayLayer, который вы создали ранее, и присвоить его self.gameplayLayer; - person giorashc; 14.05.2012
comment
Не могли бы вы привести пример? Я не уверен, что вы имеете в виду под реальным экземпляром. И, что я создал раньше, когда? - person Luke; 14.05.2012
comment
Это работает отлично. Теперь разберитесь со скоростью прокрутки. Большое спасибо за ваше терпение! - person Luke; 14.05.2012

Я не уверен, как вы можете получить доступ к heroMale, поскольку он не является членом YrrasCoastBackgroundLayer, а является членом GameplayLayer. Вам нужно будет иметь объект/экземпляр класса GameplayLayer, чтобы вы могли получить доступ к heroMale. Вот почему вы получаете необъявленный идентификатор (heroMale не является свойством класса YrrasCoastBackgroundLayer).

С уважением,
Бо

person Bo.    schedule 14.05.2012