在SpriteKit中通过节点进行触摸

4

我正在制作一款塔防游戏,目前瓦片板已经可以放置塔了,但是有些限制。

当玩家点击网格上方的按钮时,它会切换到塔放置模式,允许玩家在网格中的单元格中放置塔。然而,每个塔周围都会有一个圆形ShapeNode来处理敌人进入射程范围的检测。这个形状节点在我放置塔后就显示出来了。

我用于放置塔的逻辑是找到你触摸的节点(名为"cell"),并用一个塔节点替换它。但是如果塔节点附带的圆形节点覆盖了它旁边的一个单元格,我就无法选择圆形下面的单元格节点。

我该如何才能“穿过”这个圆形节点触摸到下面的单元格,或者将其填充空白以便我可以访问它下面的单元格?

我仍在学习Sprite-Kit,如果有更简单的方法,请随时指点我。


你的圆形节点的userInteractionEnabled属性设置为false了吗?如果你没有改变这个值,它应该默认为false。如果它是false,那么该节点就不会接收到触摸事件。 - nacross
这个方法有效,因为用户不再能够选择圆形节点,但它并没有解决用户无法选择禁用节点下方的问题,因为该节点仍然是位于其上层的节点。 - Klutch
3个回答

5
如果您想在给定点找到一个节点但不一定是最深的节点,您可以使用SKNode(包括SKScene)上可用的nodesAtPoint:
这允许您查找场景或节点的所有子节点与给定点相交。然后,您可以进一步过滤此内容以找到特定的节点,例如通过基于节点类或节点名称过滤数组。
如果要查找特定点处的物理体,则可以使用SKPhysicsWorld中可用的enumerateBodiesAtPoint:usingBlock:方法采用类似的方法。
值得注意的是,在使用nodesAtPoint:时,点位于调用节点的坐标系中,而enumerateBodiesAtPoint:usingBlock:始终位于场景的坐标系中。

这太棒了,而且运行得非常顺畅。由于我对SpriteKit还比较新,所以想了解一些基准测试。这是我创建塔放置和视图逻辑的第一个想法,但随着更多的东西添加到场景中,我可以看到它开始变得越来越滞后。 - Klutch
嗨@nacross,你能看一下我的问题吗?我在使用enumerateBodiesAtPoint时遇到了类似的问题。悬赏将在4天后结束。我尝试了所有的enumerateBodiesAt方法,但都非常不准确,我不知道为什么。https://dev59.com/FYHba4cB1Zd3GeqPUrJ8 - lisovaccaro
嗨@lisovaccaro,我觉得有一些bug,我非常确定这个功能在过去是正常工作的,但最近尝试在新游戏中使用相同的函数时遇到了问题。似乎有多个人遇到了这个问题。您可以在此处查看我的评论:https://devforums.apple.com/message/1003884#1003884 - nacross

3

没有看到您的相关代码,很难确定问题所在。从您的描述中,我认为您的问题出在形状节点上。我建议您使用塔的物理体来处理联系人,而不是使用形状节点。您仍然可以为您的塔设置圆形物理体,而无需添加整个新节点。删除形状节点也会解决交叉触摸干扰的问题。


我也在考虑这可能是我正在寻找的解决方案,但我能让物理体对玩家可见吗?因为我希望他们能看到塔射击半径。 - Klutch
1
为了保持简单,您可以考虑使用几个普通的SKSpriteNodes。每个节点中都可以有不同大小的圆形图像(当然要设置alpha值)。将zPosition设置得足够低,以免干扰其他触摸项。 - sangony
我喜欢你的想法和帮助,它们让我眼前一亮。我需要尝试一下在网格上叠加精灵层次的方法。 除非从一开始就听起来不太好,否则我还在考虑每次用户“选择”一个塔时创建和销毁圆形精灵节点,这样屏幕上只会有一个精灵,并且除非你告诉它显示出来,否则不可见。 - Klutch
你完全可以做到。这一切都取决于你如何设计你的代码以及你想让游戏玩法如何流畅/运行。祝你好运,编码愉快! - sangony
我有一个类似的问题。我有一层瓷砖(SKSpriteNodes)和一层形状节点用于调试。形状节点层被绘制到一个SKNode上,然后转换为纹理。这个纹理被叠加在游戏上作为最高z位置的节点。鉴于我的情况,你会提出什么解决方案呢?=] - Relequestual

0

TouchesBegan 自动检测该位置上的所有节点,您只需循环遍历它们。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    for (UITouch *touch in touches)
    {
        CGPoint touchPoint = [touch locationInNode:self];
        NSArray *nodes = [self nodesAtPoint:touchPoint];

        if ([nodes count])
        {
            for (SKNode *node in nodes)
            {
                if ([node.name isEqualToString:@"cell"])
                {

                }
                else
                {

                }
            }
        }
    }
}

"self" 是指触摸开始的节点(很可能是你的场景)。你也可以通过父对象进行过滤,例如;如果你将所有节点添加到名为“background”的父节点中,你可以通过用你的背景节点替换“self”来仅筛选背景节点的子节点(尽管这将导致它使用背景节点的坐标)。


如果塔的节点是SKSpriteNode的子类,则此方法无法正常工作。 - Relequestual

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接