Как сделать тап через родительские узлы?
Я искал через SO и попробовал несколько примеров, но я все еще не могу понять это поведение. На симуляторе 7.1 прохождение работает, но на 8.1 не работает. Также я задавал ранее подобный вопрос, но не такой, как этот, и я решил его с помощью метода nodeAtPoint, а затем перебрал все узлы и проверил имя / класс узла. Но это отличается, потому что теперь я использую пользовательский класс Button, который реализует touchesBegan, и я хочу, чтобы он обнаруживал и, если возможно, "глотал" касания.
Итак, у меня есть простой класс Button, который является подклассом SKSpriteNode, и у него есть свои собственные touchchesBegan и 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). Кроме того, мне было предложено подать радар из-за этого, но, как я уже сказал, я решил все с помощью nodeAtPoint вместо nodeAtPoint, поэтому я не сделал. И потому, что я думал, что это не ошибка, а скорее моя ошибка, потому что на 7.1 все было хорошо. Так это ошибка или что-то еще?
1 ответ
По иронии судьбы это похоже на ошибку с 7.1, а не 8.1 по моей математике. Я не проверял это с 7.1, хотя.
Сначала я не смог заставить ваш код работать с self.userInteractionEnabled = NO;
потому что ничто не получит прикосновений.
zPosition используется при установке ignoreSiblingsOrder
но это основано на его родителе. Таким образом, если parent равен -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. Это делает вещи еще более запутанными.