SKNode nodeAtPoint: / containsPoint: SKSpriteNode 和 SKShapeNode 的行为不同

SKNode nodeAtPoint: / containsPoint: not the same behaviour for SKSpriteNode and SKShapeNode

如果使用 SKShapeNodeSKSpriteNodenodeAtPoint: 给出的结果不同。如果我是正确的 nodeAtPoint: 将使用 containsPoint: 检查给定点处的节点。

docu 声明 containsPoint: 将使用其边界框。

我设置了一个简单的场景,在情况 1 中,圆圈是紫色节点的父级,在情况 2 中,绿色节点是紫色节点的父级。 我在这两种情况下都单击了父边界框所在的区域。

结果不同。如果我使用 SKSpriteNodenodeAtPoint: 会给我父对象。如果我使用 SKShapeNode 它 returns SKScene.

(我用鼠标按下的十字标记。)

代码:

第一次设置:

-(void)didMoveToView:(SKView *)view {
self.name = @"Scene";

SKShapeNode* circle = [SKShapeNode node];
circle.path = CGPathCreateWithEllipseInRect(CGRectMake(0, 0, 50, 50), nil);
circle.position = CGPointMake(20, 20);
circle.fillColor =  [SKColor redColor];
circle.name = @"circle";

SKSpriteNode* pnode = [SKSpriteNode node];
pnode.size = CGSizeMake(50, 50);
pnode.position = CGPointMake(50, 50);
pnode.color =  [SKColor purpleColor];
pnode.name = @"pnode";


[self addChild: circle];
[circle addChild: pnode];
}

第二个设置:

-(void)didMoveToView:(SKView *)view {
self.name = @"Scene";

SKSpriteNode* gnode = [SKSpriteNode node];
gnode.size = CGSizeMake(50, 50);
gnode.position = CGPointMake(30, 30);
gnode.color =  [SKColor greenColor];
gnode.name = @"gnode";

SKSpriteNode* pnode = [SKSpriteNode node];
pnode.size = CGSizeMake(50, 50);
pnode.position = CGPointMake(30, 30);
pnode.color =  [SKColor purpleColor];
pnode.name = @"pnode";


[self addChild: gnode];
[gnode addChild: pnode];

}

鼠标点击调用:

-(void)mouseDown:(NSEvent *)theEvent {
CGPoint location = [theEvent locationInNode:self];
NSLog(@"%@", [self nodeAtPoint: location].name);
}

我错过了什么吗?它是 SpriteKit 中的错误吗?是这样工作的吗?

简短的回答:是,不是,是

长答案...

nodeAtPoint 的文档说

returns the deepest descendant that intersects a point

并在讨论部分

a point is considered to be in a node if it lies inside the rectangle returned by the calculateAccumulatedFrame method

第一个语句适用于SKSpriteNodeSKShapeNode个节点,而第二个仅适用于SKSpriteNode个节点。对于 SKShapeNodes,Sprite Kit 忽略节点的边界框并使用 path 属性 来确定点是否与节点相交 CGPathContainsPoint。如下图所示,形状是按像素选择的,其中白点代表点击点。

图 1. 形状(蓝色)和形状 + 方形(棕色)的边界框

图 2. nodeAtPoint

的结果

calculateAccumulatedFrame returns 如下图所示相对于其父级的边界框(BB)(棕色框是正方形的 BB)。因此,如果您没有适当地为 containsPoint 调整 CGPoint,结果将不是您所期望的。要将点从场景坐标转换为父级坐标(反之亦然),请使用 convertPoint:fromNodeconvertPoint:toNode。最后,containsPoint 使用形状的 path 而不是它的边界框,就像 nodeAtPoint.