我搜索了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)。我也因此而pointed to file a radar,但正如我所说,我用nodesAtPoint而不是nodeAtPoint解决了所有问题,所以我没有。因为我认为这不是一个错误,而是我的错误,因为在7.1上一切都很好。这是一个错误,还是其他什么?
答案 0 :(得分:1)
具有讽刺意味的是,我的数学似乎是7.1而不是8.1的错误。我没有用7.1测试过这个。
首先,我无法让您的任何代码与self.userInteractionEnabled = NO;
一起使用,因为没有任何内容可以接受。
在设置ignoreSiblingsOrder
时使用zPosition,但它基于其父级。因此,如果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。它确实让事情变得更加混乱。