如何在Spritekit中通过触摸检测隐藏的SKSpriteNode?

3
我正在使用Spritekit创建一个棋盘游戏。最初所有的棋子(SKSpriteNode)都是隐藏的。它们应该在我触摸它们后出现,但由于它们被设置为隐藏,当我覆盖touchBegan函数时无法访问它们。我应该怎么做?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let location = touches.first!.locationInNode(self)
    let touchedNode = self.nodeAtPoint(location)
    if(touchedNode.name == "pieces"){
        if(touchedNode.hidden == true){
            touchedNode.hidden = false
        }
    }
}

似乎你需要重新考虑这个想法。用户怎么知道他们需要按下一个隐藏的东西呢? - pingul
请使用以下代码替换隐藏的 try alpha ? - hamobi
将节点的 alpha 属性设置为 0.0。 - Steve Ives
3个回答

2
你正在尝试的功能在iOS8上是有效的。但在iOS9中已经被修复了。如果你在iOS8上尝试你的代码,你会发现它可以工作。这是我在iOS8上感到困扰的事情之一,因为你可以点击一个隐藏的节点是没有意义的。不过,仍然可以点击alpha为0.0的节点(在iOS8上也可以),但这在iOS9中也已经被修复了。所以将alpha设置为0.0将不起作用。
解决方法:
你可以使用SKNode的containsPoint方法:
返回一个布尔值,指示一个点是否在父节点的坐标系中。
在你的情况下,“Parent”指的是你的精灵。阅读这里,了解containsPoint方法的工作原理。基本上,containsPoint不关心节点是否可见,或者是否有父节点。它只检查某个点(location)是否位于父节点(touchedNode)的坐标系内。因此,你可以使用这种方法来实现:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        let location = touches.first!.locationInNode(self)

        self.enumerateChildNodesWithName("pieces") { node, stop in

            if node.containsPoint(location) && node.hidden == true {

                node.hidden = false
                stop.memory = true
            }
        }
    }

在这里,您正在枚举所有的片段(我假设self是它们的父级),如果某个节点包含触摸位置并且它被隐藏了,那么将其设置为可见(并停止进一步、不必要的搜索)。
提示:
还应考虑在此处使用可选绑定。
if let touch = touches.first {

    let location = touch.locationInNode(self)

    //do your stuff here
}

使用可选绑定是一个好习惯,因为它更安全。

谢谢,这很有帮助。 - user3499912
@user3499912 不客气。如果这个答案帮助你解决了问题,请将其标记为已接受 ;) - Whirlwind
在iOS8上调试应用程序花费了数小时,其中一个节点没有触发touchesBegan,因为同一位置的另一个隐藏节点首先捕获了它们。我可以告诉你,苹果公司做出的修复是很好的。 - rghome

0
我有另一种方法,目前似乎正在起作用:
//如果你必须轮流进行,你可以重复使用白色磁盘循环和黑色磁盘。我使用.name来识别选择了哪个方格。
func drawBoard() {

        let numRows = 8
        let numCols = 8
        let x = scene?.size.width
        xOffset = ((x)! - ((x)! / 9) * CGFloat(numCols))
        squareSize = CGSizeMake(x!/9, x!/9)
        diskSize = CGSizeMake(x!/11, x!/11)

        // Draw the squares
        for row in 0...numRows-1 {
            for col in 0...numCols-1 {
                square = SKSpriteNode(texture: SKTexture(imageNamed: "square.png"), size: squareSize!)
                //row and column both start with zero, may want to start with 1 later
                square!.name = "square \(col)-\(row)"
                square!.userInteractionEnabled = false
                square!.position = CGPointMake(CGFloat(col) * squareSize!.width + xOffset, CGFloat(row) * squareSize!.height + xOffset)
                self.addChild(square!)
            }
        }
        // Draw the White disks "hidden"
        for row in 0...numRows-1 {
            for col in 0...numCols-1 {
                let gamePiece = SKSpriteNode(texture: SKTexture(imageNamed: "whitedisk.png"), size: diskSize!)
                gamePiece.name = "whitedisk \(col)-\(row)"
                gamePiece.userInteractionEnabled = false
                //print("Disk Name: \(gamePiece.name)")
                gamePiece.position = CGPointMake(CGFloat(col) * squareSize!.width + xOffset, CGFloat(row) * squareSize!.height + xOffset)
                gamePiece.hidden = true
                self.addChild(gamePiece)
            }
        }
}

// 磁盘变量取决于轮到谁,可能是白色磁盘或黑色磁盘 此函数确定选择了哪个方格后显示游戏棋子

func placeDisk(name: String, disk: String) {
    var myName = name
    let theDisk = disk
    myName = myName.stringByReplacingOccurrencesOfString("square", withString: theDisk)
    let node = self.childNodeWithName(myName)
    //print("Display: \(myName) - Node: \(String(node))")
    node?.hidden = false
}

// 我覆盖了touchesEND函数但你也可以使用touchesBegan

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        for touch in touches {
            let positionInScene = touch.locationInNode(self)
            let name = self.nodeAtPoint(positionInScene).name
            if name != nil {
                print("Touched: \(name)")
               placeDisk(name!, disk: "whitedisk")
            }
        }
    }

0

这是来自苹果的文档:

通过使用Alpha处理隐藏节点上的用户交互

半透明节点 - 即 alpha 值小于 1 但大于 0 的节点仍然可以接收用户交互。你可以将节点的 alpha 设置为 leastNonzeroMagnitude 来使其实际上变为透明,但仍然能够响应触摸或鼠标移动,尽管给它一个 clear 颜色 会产生相同的效果。

在我的棋盘游戏中,我有一个带有 clearcolor 的子对象。由于它没有纹理,所以它变得不可见(如果你的对象有纹理,你可以使用 leastNonzeroMagnitude)。我有一个 .sks 文件,并且像这个截图一样设置了 clear 颜色:

clear color

我选择了自定义颜色并将其不透明度设置为0。

我使用以下代码进行检测:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let location = touch.location(in: self)
        let touchedNodes = nodes(at: location)
        let frontTouchedNode = atPoint(location).name
        print(touchedNodes)
        print(frontTouchedNode!)
    }

更多信息请参考官方苹果文章链接:控制节点上的用户交互


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