Набор спрайтов: опорная точка меняет фактическое положение спрайта

пожалуйста, помогите мне разобраться в этой путанице.

Из руководства по программированию Sprite Kit:

Свойство anchorPoint узла спрайта определяет, какая точка кадра находится в позиции спрайта.

Насколько я понимаю, если я изменю Anchor Point, позиция спрайта должна остаться неизменной, и соответственно будет перемещена только рендеринг текстуры.

Но когда я устанавливаю точку привязки, положение моего спрайта действительно меняется! Взгляните на этот фрагмент:

/* debug */
if (self.currentState == self.editState) {
    printf("B: relativeAnchorPoint = %.02f,%.02f  ", relativeAnchorPoint.x, relativeAnchorPoint.y);
    printf("position = %.02f,%.02f\n",self.position.x, self.position.y);
}

[self setAnchorPoint:relativeAnchorPoint];

/* debug */
if (self.currentState == self.editState) {
    printf("A: relativeAnchorPoint = %.02f,%.02f  ", relativeAnchorPoint.x, relativeAnchorPoint.y);
    printf("position = %.02f,%.02f\n",self.position.x, self.position.y);
}

Выход:

A: относительныйAnchorPoint = 0,65,0,48 position = 1532,00,384,00

B: относительная АнчорПойнт = 0,65,0,48 позиция = 1583,00,384,00

Что мне не хватает?

заранее спасибо

*edit: дополнительная информация: * это происходит только тогда, когда мой спрайт имеет xScale равным -1 для инвертирования изображения


person Spinn80    schedule 30.07.2014    source источник
comment
Позиция спрайта — это точка привязки, поэтому он перемещается, когда вы меняете точку привязки.   -  person 0x141E    schedule 30.07.2014
comment
@Code Monkey, что является заблуждением, положение узла там, где оно находится, anchorPoint не изменяет (не должен) положение узла, он только определяет, где - по отношению к положению узла - рисуется текстура узла   -  person LearnCocos2D    schedule 30.07.2014
comment
@LearnCocos2D спасибо, что разъяснили это.   -  person 0x141E    schedule 30.07.2014
comment
Возможно, было бы лучше не устанавливать для xScale значение -1, а вместо этого инвертировать изображение с помощью приложения «Просмотр» («Инструменты» > «Отразить по горизонтали»).   -  person 0x141E    schedule 30.07.2014
comment
@CodeMonkey, инвертирование изображения должно выполняться на лету, так как я не хочу иметь дубликат изображения каждого спрайта в моем коде, что было бы огромной тратой памяти ...   -  person Spinn80    schedule 30.07.2014


Ответы (1)


Я сделал быстрый тест, чтобы подтвердить ваше наблюдение, и оно действительно верно.

Поскольку xScale становится отрицательным, anchorPoint действительно влияет на позицию узла.

Я склонен думать об этом как о ошибке, поскольку, по-видимому, нет корреляции между отрицательным значением xScale и увеличением положения x. И это нельзя считать нормальным поведением.

Также это происходит только тогда, когда вы меняете anchorPoint после того, как xScale уже является отрицательным. Вы можете установить anchorPoint, затем изменить xScale как хотите, и все будет хорошо, позиция не изменится.

Я подтвердил, что эта проблема существует как в Xcode 5.1 (iOS 7), так и в бета-версии Xcode 6 (бета-версия iOS 8).

Если вы запустите следующий код во вновь созданном проекте Sprite Kit вместо его автоматически созданного файла MyScene.m, вы увидите, что при случайном изменении anchorPoint между 0,0 и 1,0 положение спрайта всегда остается неизменным до тех пор, пока свойство xScale изменяется на отрицательное значение. В этот момент position.x начинает значительно увеличиваться.

#import "MyScene.h"

@implementation MyScene
{
    SKSpriteNode *sprite;
}
-(id) initWithSize:(CGSize)size
{
    if (self = [super initWithSize:size])
    {
        self.backgroundColor = [SKColor colorWithRed:0 green:0 blue:0.2 alpha:1];

        sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];
        sprite.position = CGPointMake(CGRectGetMidX(self.frame),
                                       CGRectGetMidY(self.frame));
        sprite.anchorPoint = CGPointMake(0.2, 0.7);
        [self addChild:sprite];

        SKAction *action = [SKAction scaleXTo:-1.0 duration:10];
        [sprite runAction:[SKAction repeatActionForever:action]];
    }
    return self;
}
-(void) update:(CFTimeInterval)currentTime
{
    sprite.anchorPoint = CGPointMake(arc4random_uniform(10000) / 10000.0,
                                     arc4random_uniform(10000) / 10000.0);

    NSLog(@"pos: {%.1f, %.1f}, xScale: %.3f, anchor: {%.2f, %.2f}",
          sprite.position.x, sprite.position.y, sprite.xScale,
          sprite.anchorPoint.x, sprite.anchorPoint.y);
}
@end

Для этой ошибки существует обходной путь:

Если xScale уже имеет отрицательное значение, инвертируйте его, затем установите anchorPoint, а затем повторно инвертируйте xScale. Возможно, вам придется сделать то же самое с yScale, если он тоже может стать отрицательным.

Следующий метод обновления включает этот обходной путь, и я подтвердил, что он работает должным образом:

-(void) update:(CFTimeInterval)currentTime
{
    BOOL didInvert = NO;
    if (sprite.xScale < 0.0)
    {
        didInvert = YES;
        sprite.xScale *= -1.0;
    }

    sprite.anchorPoint = CGPointMake(arc4random_uniform(10000) / 10000.0,
                                     arc4random_uniform(10000) / 10000.0);

    if (didInvert)
    {
        sprite.xScale *= -1.0;
    }

    NSLog(@"pos: {%.1f, %.1f}, xScale: %.3f, anchor: {%.2f, %.2f}",
          sprite.position.x, sprite.position.y, sprite.xScale, 
          sprite.anchorPoint.x, sprite.anchorPoint.y);
}

Sprite.position теперь остается неизменным на протяжении всей продолжительности действия scaleXTo.

person LearnCocos2D    schedule 30.07.2014
comment
Вы забыли установить didInvert в первом операторе if. - person 0x141E; 30.07.2014
comment
@LearnCocos2D, спасибо за подсказку. Есть ли способ уведомить об этом Apple? - person Spinn80; 30.07.2014
comment
Да, здесь: developer.apple.com/bug-reporting Обязательно добавьте ссылку к этому сообщению, я думаю, что это объясняет проблему достаточно хорошо. - person LearnCocos2D; 30.07.2014