In learning SpriteKit, I am trying to make a small adventure game. I am creating a hero, and adding it to the scene, and then later, during touchesBegan:
, I detect if the touch originated on the hero, and take actions accordingly.
在学习SpriteKit时,我正在尝试制作一款小型冒险游戏。我正在创建一个英雄,并将其添加到场景中,然后在touchesBegan:中,我检测到触摸是否源自英雄,并采取相应的操作。
If I add the hero as a SKSpriteNode
the touch detects him. If I add him as a subclass of SKSpriteNode
the touch does not! The difference in adding:
如果我将英雄添加为SKSpriteNode,则触摸会检测到他。如果我将他添加为SKSpriteNode的子类,则触摸不会!添加的区别:
_heroNode = [SKSpriteNode spriteNodeWithImageNamed:@"hero.png"];
vs
_heroNode = [[ADVHeroNode alloc] init];
The init looks like this:
init看起来像这样:
- (id) init {
if (self = [super init]) {
self.name = @"heroNode";
SKSpriteNode *image = [SKSpriteNode spriteNodeWithImageNamed:@"hero.png"];
[self addChild:image];
}
return self;
}
Adding the hero as a subclass of SKSpriteNode works in the sense that it is added to the scene, but the touch doesn't detect him. My touchesBegan:
looks like this:
将英雄添加为SKSpriteNode的子类可以将其添加到场景中,但触摸不会检测到他。我的touchesBegan:看起来像这样:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if (YES) NSLog(@"Node name where touch began: %@", node.name);
//if hero touched set BOOL
if ([node.name isEqualToString:@"heroNode"]) {
if (YES) NSLog(@"touch in hero");
touchedHero = YES;
}
}
Frustratingly, this code works just fine when adding a straight up SKSpriteNode
, and not my own subclass of it. Any suggestions?
令人沮丧的是,这个代码在添加一个直接的SKSpriteNode时工作得很好,而不是我自己的子类。有什么建议?
5 个解决方案
#1
23
Here are some example ways to subclass your Hero
以下是一些子类化Hero的示例方法
SKNode
Subclass an SKNode
this method requires your node to monitor for touches, hence the self.userInteractionEnabled property.
子类化SKNode此方法需要您的节点监视触摸,因此需要self.userInteractionEnabled属性。
@implementation HeroSprite
- (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(@"Hit at, %@ %@", NSStringFromCGPoint(locationA), NSStringFromCGPoint(locationB));
}
@end
SKSpriteNode
The other "easier" way, if you just want to subclass a SKSpriteNode
. This will work essentially the same as you are use to (before you wanted to subclass your Hero). So your touchesBegan, as set up in your question will work.
另一种“更简单”的方式,如果您只想子类化SKSpriteNode。这将与您习惯使用的基本相同(在您想要继承Hero之前)。所以你的touchesBegan,在你的问题中设置将起作用。
@implementation HeroSprite
- (id) init {
if (self = [super init]) {
self = [HeroSprite spriteNodeWithImageNamed:@"Spaceship"];
[self setUpHeroDetails];
}
return self;
}
-(void) setUpHeroDetails {
self.name = @"heroNode";
}
@end
#2
10
Just be sure to add this in your init method.
请务必在init方法中添加它。
self.userInteractionEnabled = YES;
For some reasons this is not enabled by default when you subclass. At least for me it worked only when manually enabled.
由于某些原因,在子类化时默认情况下不启用此选项。至少对我来说,它仅在手动启用时才有效。
#3
3
I usually check the touched node's parent until i find the class i want to control. Here's a code snippet.
我经常检查触摸节点的父节点,直到找到我想要控制的类。这是一段代码片段。
while (touchedNode.parent)
{
if ([touchedNode isKindOfClass:[GameObject class]])
break;
else
touchedNode = (SKSpriteNode*)self.touchedNode.parent;
}
#4
1
It just detected touch on this sprite only.
它只检测到这个精灵的触摸。
When you create an Object SKSpriteNode, it will control itself. It mean, when a touch begin on it, it mean this object receive this touch not the SKView.
当您创建一个Object SKSpriteNode时,它将控制自己。这意味着,当触摸开始时,它意味着此对象接收此触摸而不是SKView。
So if you want to detect this touch, you must write this code on this object not on the SKView. If you want to do anything on SKView when a touch happen on SKSpriteNode, you can use delegate to do this.
因此,如果要检测此触摸,则必须在此对象上编写此代码,而不是在SKView上。如果您想在SKSpriteNode上进行触摸时在SKView上执行任何操作,则可以使用委托执行此操作。
Feel free to ask more if you cannot understand what I answer.
如果您无法理解我的答案,请随时询问更多。
#5
0
Your ADVHeroNode is either a SkNode or SkSpriteNode with no image. Neither will have any extents, they're points so to speak. They will not be found by nodeAtPoint: but the image child SKSpriteNode will. Since you're explicitly checking for the node's name, the check fails.
您的ADVHeroNode是没有图像的SkNode或SkSpriteNode。它们都没有任何范围,它们可以说是重点。 nodeAtPoint将找不到它们:但是图像子SKSpriteNode将会找到它们。由于您明确检查节点的名称,因此检查失败。
You could give the image a name, and check for that and then refer to its parent to gethe ADVHeronode instance. Or just check node.parent's name directly.
您可以为图像指定名称,然后检查它,然后引用其父级以获取ADVHeronode实例。或者直接检查node.parent的名称。
#1
23
Here are some example ways to subclass your Hero
以下是一些子类化Hero的示例方法
SKNode
Subclass an SKNode
this method requires your node to monitor for touches, hence the self.userInteractionEnabled property.
子类化SKNode此方法需要您的节点监视触摸,因此需要self.userInteractionEnabled属性。
@implementation HeroSprite
- (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(@"Hit at, %@ %@", NSStringFromCGPoint(locationA), NSStringFromCGPoint(locationB));
}
@end
SKSpriteNode
The other "easier" way, if you just want to subclass a SKSpriteNode
. This will work essentially the same as you are use to (before you wanted to subclass your Hero). So your touchesBegan, as set up in your question will work.
另一种“更简单”的方式,如果您只想子类化SKSpriteNode。这将与您习惯使用的基本相同(在您想要继承Hero之前)。所以你的touchesBegan,在你的问题中设置将起作用。
@implementation HeroSprite
- (id) init {
if (self = [super init]) {
self = [HeroSprite spriteNodeWithImageNamed:@"Spaceship"];
[self setUpHeroDetails];
}
return self;
}
-(void) setUpHeroDetails {
self.name = @"heroNode";
}
@end
#2
10
Just be sure to add this in your init method.
请务必在init方法中添加它。
self.userInteractionEnabled = YES;
For some reasons this is not enabled by default when you subclass. At least for me it worked only when manually enabled.
由于某些原因,在子类化时默认情况下不启用此选项。至少对我来说,它仅在手动启用时才有效。
#3
3
I usually check the touched node's parent until i find the class i want to control. Here's a code snippet.
我经常检查触摸节点的父节点,直到找到我想要控制的类。这是一段代码片段。
while (touchedNode.parent)
{
if ([touchedNode isKindOfClass:[GameObject class]])
break;
else
touchedNode = (SKSpriteNode*)self.touchedNode.parent;
}
#4
1
It just detected touch on this sprite only.
它只检测到这个精灵的触摸。
When you create an Object SKSpriteNode, it will control itself. It mean, when a touch begin on it, it mean this object receive this touch not the SKView.
当您创建一个Object SKSpriteNode时,它将控制自己。这意味着,当触摸开始时,它意味着此对象接收此触摸而不是SKView。
So if you want to detect this touch, you must write this code on this object not on the SKView. If you want to do anything on SKView when a touch happen on SKSpriteNode, you can use delegate to do this.
因此,如果要检测此触摸,则必须在此对象上编写此代码,而不是在SKView上。如果您想在SKSpriteNode上进行触摸时在SKView上执行任何操作,则可以使用委托执行此操作。
Feel free to ask more if you cannot understand what I answer.
如果您无法理解我的答案,请随时询问更多。
#5
0
Your ADVHeroNode is either a SkNode or SkSpriteNode with no image. Neither will have any extents, they're points so to speak. They will not be found by nodeAtPoint: but the image child SKSpriteNode will. Since you're explicitly checking for the node's name, the check fails.
您的ADVHeroNode是没有图像的SkNode或SkSpriteNode。它们都没有任何范围,它们可以说是重点。 nodeAtPoint将找不到它们:但是图像子SKSpriteNode将会找到它们。由于您明确检查节点的名称,因此检查失败。
You could give the image a name, and check for that and then refer to its parent to gethe ADVHeronode instance. Or just check node.parent's name directly.
您可以为图像指定名称,然后检查它,然后引用其父级以获取ADVHeronode实例。或者直接检查node.parent的名称。