检测节点是否触摸框架的最佳方法

时间:2017-11-12 18:26:24

标签: swift sprite-kit sknode skshapenode

我正在使用SpriteKit构建一些游戏,包括球作为SKShapeNode。我创建了一个定义球及其属性的类(包括SKPhysicsBody)。球应该在屏幕上运行,框架是屏幕边框(通过使用edgeLoopF​​rom:self.frame)。我还创建了一个位于屏幕顶部的路径节点。现在,我想这样做,如果一些球到达框架的顶部边界,所以一些功能将执行。 我读了一些关于它的内容并且我不确定这样做的正确方法是什么,如果使用contactBitMask或者是否有其他更好的选择。 如果正确的方法是通过contactBitMask - 我是否必须为ball节点设置一个结构,或者我可以在它们的类中设置它? 谢谢!

1 个答案:

答案 0 :(得分:1)

如果我做对了,当一个球击中位于屏幕上半部分的路径节点时,你想要一个函数被调用。

首先,我不确定路径节点是否比精灵节点更有效,事实上我从未真正使用路径节点,但这是你可以做的。

Spritekit

查看上面的链接。您需要做的是实施 SKPhysicsContactDelegate 。这将允许您访问函数didBegin()和didEnd()。在physicsworld中建立联系时会调用这些函数。

class YourClass: SKScene, SKPhysicsContactDelegate {
    func didBegin(_ contact: SKPhysicsContact) {
    }

    func didEnd(_ contact: SKPhysicsContact) {
    }
}

为了调用这些函数,您需要将physicsworld的contactDelegate设置为将处理调用的类。这将是你的场景,设置它的好地方是didMove()函数。

class YourClass: SKScene, SKPhysicsContactDelegate {
    func didMove(to view: SKView) {
        physicsWorld.contactDelegate = self
    }

现在当发生可检测的联系时,将调用您的didBegin(),当联系结束时,将调用didEnd()。

现在我们需要为我们的节点提供一些物理实体,我们可以在它们上设置不同的位掩码以检测碰撞/接触。这些是我们关注的3位掩码:

categoryTestBitMask
collisionTestBitMask
contactTestBitMask

categoryTestBitMask:您可以为类似类型的节点提供类别,例如" ball"可以是类别。您所有不同的球对象都可以具有相同的类别。我使用" noCollision"我希望检测联系人时的类别,但我不希望发生碰撞。你被限制在32个不同的类别,但不要因为大量不同的类别而疯狂。

collisionTestBitMask:给你的"球"您希望发生碰撞的类别。例如:为你的"球"设置碰撞测试掩码。到" wall"的类别位掩码。碰撞是指两个物体彼此物理碰撞;所以你的球会从墙上反弹。

contactTestBitMask: a联系人是2个节点重叠的时间。因此,不是球反弹,而是为我们的代表调用联系方式。请注意,您可以将碰撞和接触位掩码设置为相同的东西。

现在我们如何设置这些面具。我使用一个Struct,以便我可以为位掩码分配名称,并使用代码设置这3个不同的掩码。像这样:

struct Mask {
static var ball: UInt32 = 0b10 //2
static var wall: UInt32 = 0b100 //4
static var pathNode: UInt32 = 0b1000 //8
}

现在在代码中你可以设置掩码:

let ball = SKSpriteNode()
ball.name = "ball"
ball.physicsBody = SKPhysicsBody()
ball.physicsBody.categoryTestBitMask = Mask.ball
ball.physicsBody.collisionTestBitMask = Mask.wall
ball.physicsBody.contactTestBitMask = Mask.pathNode | Mask.wall

let pathNode = SKSpriteNode()
pathNode.name = "pathNode"
pathNode.physicsBody = SKPhysicsBody()
pathNode.physicsBody.categoryTestBitMask = Mask.pathNode
pathNode.physicsBody.collisionTestBitMask = 0
pathNode.physicsBody.contactTestBitMask = Mask.pathNode

让我们看看我们在这里说的话。我们创建了一个球对象,我们将其类别设置为" ball",我们说我们希望它与" wall"对象,我们希望我们的联系委托函数用" pathNode"触发。对象 OR " wall"对象。我们的pathNode对象没有碰撞,并且会与球有接触。

基本上球将从墙壁反弹,并将通过pathNode。它将使用pathNode和wall对象调用联系委托函数didbegin()和didend()。

尚未完成......所以当调用该函数时,我们该如何处理?当调用didbegin或didend函数时,它的参数为" contact"。这个联系方式有2个可以使用的实体,这些是相互联系的实体。我们有多种方法可以解决这个问题,但我现在只是向您展示一种简单的方法。

func didBegin(_ contact: SKPhysicsContact) {
    if contact.bodyA!.node!.name == "ball" {
    // bodyA is our ball
        switch contact.bodyB!.node!.name {
        case "pathNode":
            thisIsMyBallHitPathNodeFunction()
        case "wall":
            thisIsMyBallHitWallFunction()
        default:
            break
        }
    }
    else if contact.bodyB!.node!.name == "ball" {
    // bodyB is our ball
        switch contact.bodyA!.node!.name {
        case "pathNode":
            thisIsMyBallHitPathNodeFunction()
        case "wall":
            thisIsMyBallHitWallFunction()
        default:
            break
        }

    }

}

<强>更新: 我们在这里做的是弄清bodyA和bodyB的类型。所以它从bodyA开始,如果bodyA是&#34;球&#34;,那么我们知道bodyA是&#34;球和bodyB是球接触的东西。然后我们使用switch语句来确定bodyB是什么。一旦我们知道bodyB是什么,我们就会调用我们需要为这两个节点之间的特定联系调用的函数。

然后,您只需将代码放入您想要执行的指定功能中。

这可能会立刻吸收很多东西,如果你是新手,我会建议尝试一下并试图让它发挥作用。之后,我会推荐一些关于如何做到这一点的视频。看看不同的人如何处理同样的事情是一个好主意,然后你可以自己决定如何做到这一点。这可能不是处理联系人最优雅的方式,但它运作良好,通过一些练习,它将成为第二天性,祝你好运!