SKNode nodeAtPoint: / containsPoint: не е същото поведение за SKSpriteNode и SKShapeNode

nodeAtPoint: не дава същия резултат, ако използвате SKShapeNode и SKSpriteNode. Ако съм прав, nodeAtPoint: ще използва containsPoint:, за да провери кои възли са в дадената точка.

docu заявява, че containsPoint: ще използва своята ограничаваща рамка.

Настроих проста сцена, където в ситуация 1 кръгът е родител на лилавия възел, а в ситуация 2 зеленият възел е родител на лилавия възел. Щракнах и в двата случая в област, където трябва да бъде ограничителната рамка на родителя.

Резултатът е различен. Ако използвам SKSpriteNode, nodeAtPoint: ще ми даде родителя. Ако използвам SKShapeNode, той връща 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? Предназначено ли е да работи по този начин?


person NieLernend    schedule 14.08.2015    source източник


Отговори (1)


Кратките отговори: да, не, да

Дългият отговор...

В документацията за nodeAtPoint се казва, че то

връща най-дълбокия потомък, който пресича точка

и в секцията Дискусия

счита се, че точка е във възел, ако се намира вътре в правоъгълника, върнат от метода calculateAccumulatedFrame

Първото твърдение се отнася за SKSpriteNode и SKShapeNode възли, докато второто се отнася само за SKSpriteNode възли. За SKShapeNodes Sprite Kit игнорира ограничителната кутия на възела и използва свойството path, за да определи дали дадена точка пресича възела с CGPathContainsPoint. Както е показано на фигурите по-долу, формите се избират на базата на пиксел, където белите точки представляват точките на щракване.

Ограничаваща кутия за възел на фигура

Фигура 1. Ограничаващи полета за форма (синьо) и форма + квадрат (кафяво)

containsPoint Test

Фигура 2. Резултати от nodeAtPoint

calculateAccumulatedFrame връща ограничителна кутия (BB), която е относителна към своя родител, както е показано на фигурата по-долу (кафявата кутия е BB на квадрата). Следователно, ако не коригирате CGPoint за containsPoint по подходящ начин, резултатите няма да бъдат това, което сте очаквали. За да конвертирате точка от координати на сцена в координати на родител (или обратно), използвайте convertPoint:fromNode или convertPoint:toNode. И накрая, containsPoint използва path на фигура вместо нейната ограничаваща рамка точно като nodeAtPoint.

въведете описание на изображението тук

person 0x141E    schedule 15.08.2015
comment
Но защо SpriteKit е толкова непоследователен? Очаквах, че връщането на nodeAtPoint: ще бъде или възелът, който виждам в точката, или друг последователен резултат. Като използването на натрупаната рамка. Сега това силно зависи от типа възли, който може дори да е различен за други типове възли ... - person NieLernend; 19.08.2015
comment
Ако имате нужда от последователно поведение, можете да използвате един и същ подклас на възел (напр. SKSpriteNode) за всички ваши игрови обекти. Можете да създавате фигури (напр. кръгове, многоъгълници) с приложение за редактиране на изображения. - person 0x141E; 20.08.2015
comment
За съжаление това не е подходящо за моята употреба. Създавам рамка, която ми позволява да разпознавам докосвания на почти всеки входен хардуер в MacOS SpriteKit приложения. Така че не мога да огранича всеки потребител на моята рамка да използва само SpriteNodes. Този проблем с несъответствието възниква, когато се опитвам да идентифицирам кой възел е бил натиснат. Вероятно ще го направя последователен, като не използвам nodeAtPoint, а като проверявам сам натрупаните рамки. Жалко е, но все пак благодаря за помощта. - person NieLernend; 20.08.2015
comment
Също така един допълнителен въпрос. Откъде знаеш, че containsPoint: ще използва пътя на фигурите? В документацията се посочва, че containsPoint: всъщност трябва да използва ограничителната кутия ... - person NieLernend; 24.08.2015
comment
Създадох проект, който показва резултатите от containsPoint: подобно на това, което направих с nodeAtPoint: на Фигура 2. Щраквайки във и около кръговия възел, заключих, че Sprite Kit използва пътя на кръга вместо неговата ограничаваща кутия. - person 0x141E; 24.08.2015