Как сделать тап через родительские узлы?

Я искал через SO и пробовал несколько примеров, но я до сих пор не могу понять это поведение. На симуляторе 7.1 сквозное подключение работает, но на 8.1 не работает. Также я задавал ранее аналогичный вопрос, но не такой, как этот, и я решил его, используя метод nodesAtPoint, а затем перебрал все узлы и проверил имя/класс узла. , Но это отличается, потому что теперь я использую собственный класс Button, который реализует touchesBegan, и я хочу, чтобы он обнаруживал и, если возможно, «проглатывал» касания.

Итак, у меня есть простой класс Button, который является подклассом SKSpriteNode, и у него есть свои TouchesBegan и userInteractionEnabled = YES. В моем представлении свойство контроллера ignoreSiblingsOrder установлено на YES.

Вот (упрощенный) пример, который может привести к описанному поведению:

#import "GameScene.h"

@interface Button : SKSpriteNode
-(instancetype)initWithColor:(UIColor *)color size:(CGSize)size;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
@end


@implementation Button
-(instancetype)initWithColor:(UIColor *)color size:(CGSize)size {
    self = [super initWithColor:color size:size];
    self.userInteractionEnabled = YES;
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"%@ hit", self.name);
}
@end

@implementation GameScene

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {

        self.userInteractionEnabled = NO;

        SKNode* root = [SKNode new];
        root.name = @"root";
        SKNode* layer1 = [SKNode new];
        SKNode* layer2 = [SKNode new];

        layer1.zPosition = -1;//layer1 and layer2 are just containers
        layer2.zPosition = -2;


        Button* button = [Button spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(100, 100)];
        button.name = @"yellow button";
        button.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));

        [layer1 addChild:button];

        [root addChild:layer1];
        [root addChild:layer2];

        [self addChild:root];

    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    NSLog(@"Touch detected");
}

@end

Я просто не понимаю, почему это не работает в 8.1... Я знаю, что проверка на попадание идет в порядке, противоположном рендерингу узлов, но тогда как правильно добиться сквозного поведения? Итак, в настоящее время происходит то, что когда я тестирую на 7.1, я получаю сообщение «желтая кнопка», но на 8.1 я получаю сообщение «обнаружено касание» (и когда я печатаю имя узла, он говорит root). Кроме того, из-за этого мне написали радар , но, как я уже сказал, я решил все с помощью nodesAtPoint вместо nodeAtPoint, поэтому я этого не делал. А потому я думал, что это не баг, а скорее моя ошибка, ведь на 7.1 все было нормально. Так это баг или что-то другое?


person Whirlwind    schedule 03.04.2015    source источник


Ответы (1)


По иронии судьбы, по моим расчетам, это ошибка 7.1, а не 8.1. Я не тестировал это с 7.1, хотя.

Сначала я не мог заставить ваш код работать с self.userInteractionEnabled = NO;, потому что ничего не получалось.

zPosition используется, когда вы устанавливаете ignoreSiblingsOrder, но он основан на его родительском элементе. Так что, если родитель равен -1, а вы добавляете дочерний элемент с 0, его рендеринг zPosition по-прежнему равен -1. То же самое и с касаниями, но в обратном порядке. Последний, обработанный с помощью userInteraction, получает событие касания.

Надеюсь, это имеет смысл. Смотрите добавленные комментарии и отладку.

#import "GameScene.h"

@interface Button : SKSpriteNode
-(instancetype)initWithColor:(UIColor *)color size:(CGSize)size;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
@end


@implementation Button
-(instancetype)initWithColor:(UIColor *)color size:(CGSize)size {
    self = [super initWithColor:color size:size];
    self.userInteractionEnabled = YES;
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"%@ hit", self.name);
}
@end

@implementation GameScene

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {

        SKNode* root = [SKNode new];
        root.name = @"root";

        SKNode* layer1 = [SKNode new];
        layer1.name = @"layer1";

        SKNode* layer2 = [SKNode new];
        layer2.name = @"layer2";

        layer1.zPosition = -1;//layer1 and layer2 are just containers
        layer2.zPosition = -2;


        Button* button = [Button spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(100, 100)];
        button.name = @"yellow button";
        button.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));

        //layer1 is at -1 and button does not have a z so it will be -1 in the scene like its parent (-1+0)
        [layer1 addChild:button];

        //root is 0 layer1 is -1 (along with button) root is above layer1 and will recieve any touches
        [root addChild:layer1];

        //root is 0 layer2 is -2 layer1 (and button) are above layer2 and root is above layer1 root gets touch
        [root addChild:layer2];

        //nothing changes except root is added
        [self addChild:root];

        //button needs to be on same zPosition or higher to get touch
        //it is -1 because of parent node + 1 = 0
        //best if you do +2 to ensure it is above

//        button.zPosition = 2;

    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    for (UITouch *touch in touches)
    {
        CGPoint point = [touch locationInNode:self];
        SKNode *node = [self nodeAtPoint:point];
        NSLog(@"Touch detected: %@", node.name);
    }

}

Также я бы посоветовал не использовать отрицательное число для zPosition. Это делает вещи еще более запутанными.

person Skyler Lauren    schedule 04.04.2015
comment
Ага, спасибо... Я запутался, потому что разные симуляторы дают разные результаты, и я не знал, какой из них правильный. Я думал, что 7.1 работает нормально. Установка zPosition кнопки выше, чем zPosition родителя, решила проблему. - person Whirlwind; 04.04.2015