我放了一个精灵A(用于接收命中的子类(userInteractionEnabled为YES)),然后是一个普通的精灵B,它不会在其上面点击(userInteractionEnabled默认为NO),完全覆盖精灵A.
点击精灵B,我假设精灵A会触摸但没有任何反应。关于此事的文档部分如下。
我觉得这里有些东西不清楚,因为看起来精灵B仍然接受了触摸但却把它扔了。 或者,spriteA从可能的触摸接收器中移除,因为它不可见。
对于在命中测试期间要考虑的节点,它 userInteractionEnabled属性必须设置为YES。默认值 除场景节点外的任何节点都为NO。想要接收的节点 事件需要从它实现适当的响应方法 父类(iOS上的UIResponder和OS X上的NSResponder)。这是一 您必须在其中实现特定于平台的代码的几个地方 精灵套件
无论如何解决这个问题? 只要某个用户的userInteractionEnabled为NO,就不应该干扰其他触摸接收器。
更新:即使将精灵B的alpha设置为0.2,使精灵A非常可见,也不会使精灵A可触摸。 Sprite B完全“吞下”了触摸,尽管没有启用交互。
答案 0 :(得分:10)
这是我的解决方案,直到Apple以正确的行为更新SpriteKit,或者有人按照我们想要的方式实际知道如何使用它。
https://gist.github.com/bobmoff/7110052
将文件添加到项目中并将其导入Prefix标头中。现在接触应该按照预期的方式工作。
答案 1 :(得分:2)
我的解决方案不需要isKindOfClass类的东西......
在您的SKScene界面中:
@property (nonatomic, strong) SKNode* touchTargetNode;
// this will be the target node for touchesCancelled, touchesMoved, touchesEnded
在您的SKScene实施中
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
NSArray* nodes = [self nodesAtPoint:[touch locationInNode:self]];
self.touchTargetNode = nil;
for( SKNode* node in [nodes reverseObjectEnumerator] )
{
if( [node conformsToProtocol:@protocol(CSTouchableNode)] )
{
SKNode<CSTouchableNode>* touchable = (SKNode<CSTouchableNode>*)node;
if( touchable.wantsTouchEvents )
{
self.touchTargetNode = node;
[node touchesBegan:touches
withEvent:event];
break;
}
}
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.touchTargetNode touchesCancelled:touches
withEvent:event];
self.touchTargetNode = nil;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.touchTargetNode touchesMoved:touches
withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.touchTargetNode touchesEnded:touches
withEvent:event];
self.touchTargetNode = nil;
}
您需要定义CSTouchableNode协议...根据您的意愿调用它:)
@protocol CSTouchableNode <NSObject>
- (BOOL) wantsTouchEvents;
- (void) setWantsTouchEvents:(BOOL)wantsTouchEvents;
@end
对于您想要触摸的SKNode,它们需要符合CSTouchableNode协议。您需要根据需要在课程中添加类似下面的内容。
@property (nonatomic, assign) BOOL wantsTouchEvents;
这样做,点击节点可以正常工作。当Apple修复“userInteractionEnabled”错误时,它不会破坏。是的,这是一个错误。一个愚蠢的小虫。傻苹果。
<强>更新强>
SpriteKit中还有另一个错误......节点的z顺序很奇怪。我已经看到了奇怪的节点排序......因此我倾向于为需要它的节点/场景强制使用zPosition。
我已经更新了我的SKScene实现,以便根据zPosition对节点进行排序。
nodes = [nodes sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"zPosition" ascending:false]]];
for( SKNode* node in nodes )
{
...
}
答案 2 :(得分:1)
以下是获取触摸等的示例。
场景
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
HeroSprite *newHero = [HeroSprite new];
newHero.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild:newHero];
SKSpriteNode *overLapSprite = [SKSpriteNode spriteNodeWithColor:[UIColor orangeColor] size:CGSizeMake(70, 70)];
overLapSprite.position = CGPointMake(CGRectGetMidX(self.frame) + 30, CGRectGetMidY(self.frame));
overLapSprite.name = @"overlap";
[self addChild:overLapSprite];
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:@"heroNode"]) {
NSLog(@"Scene detect hit on hero");
}
if ([node.name isEqualToString:@"overlap"]) {
NSLog(@"overlap detect hit");
}
// go through all the nodes at the point
NSArray *allNodes = [self nodesAtPoint:location];
for (SKNode *aNode in allNodes) {
NSLog(@"Loop; node name = %@", aNode.name);
}
}
Subclassed sprite / Hero
- (id) init {
if (self = [super init]) {
[self setUpHeroDetails];
self.userInteractionEnabled = YES;
}
return self;
}
-(void) setUpHeroDetails
{
self.name = @"heroNode";
SKSpriteNode *heroImage = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];
[self addChild:heroImage];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint locationA = [touch locationInNode:self];
CGPoint locationB = [touch locationInNode:self.parent];
NSLog(@"Hero got Hit at, %@ %@", NSStringFromCGPoint(locationA), NSStringFromCGPoint(locationB));
}
@end
尝试过很多东西,但触摸不会经过重叠的精灵。我想你可以使用场景类通过循环遍历节点来检测触摸,然后直接调用该节点。
当粒子发射器覆盖按钮时,我遇到了这个问题...
答案 3 :(得分:1)
我认为这可能是一种设计选择,但肯定不是很灵活。我喜欢在场景级别的Sprite Kit中使用nodeAtPoint处理可以重叠的对象(如游戏对象):结合isKindOfClass:方法。对于通常不重叠并放置在不同图层(如叠加和按钮)的按钮等对象,我在其类中处理用户交互。 我希望我的触摸事件能够在Sparrow Framework中“冒泡”节点树,但我担心它更像是一个功能请求而不是错误报告。
P.S。:通过处理场景级别的触摸,您可以轻松地触摸和移动节点,即使它们被不可移动和不可触摸的节点完全覆盖!
答案 4 :(得分:1)
使用更少行代码的解决方案。请记住在要接收的每个节点中设置userInteractionEnabled。
- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer {
CGPoint touchLocation = self.positionInScene;
SKSpriteNode *touchedNode = (SKSpriteNode *)[self nodeAtPoint:touchLocation];
NSArray *nodes = [self nodesAtPoint:touchLocation];
for (SKSpriteNode *node in [nodes reverseObjectEnumerator]) {
NSLog(@"Node in touch array: %@. Touch enabled: %hhd", node.name, node.isUserInteractionEnabled);
if (node.isUserInteractionEnabled == 1)
touchedNode = node;
}
NSLog(@"Newly selected node: %@", touchedNode);
}