SKPhysicsContactDelegate обнаружение столкновений с помощью Swift

Я пытаюсь решить проблему с обнаружением столкновений SKPhysicsContactDelegate. У меня есть два узла, узел A и узел B, узел A находится на экране неподвижно, в то время как узел B может перемещаться по экрану пальцем пользователя. узел A должен иметь возможность определять, перекрывает ли его узел B. Методы didBeginContact и didEndContact вызываются несколько раз, что в ходе исследований я обнаружил, что это ожидаемое поведение. Чтобы обойти эту проблему, я просто установил целочисленную переменную в 0 и увеличивал ее каждый раз, когда был контакт, и уменьшал ее каждый раз, когда контакт заканчивался. Если значение больше 0, тогда два узла перекрываются, а если значение равно 0, то это не так. Это работает нормально, пока пользователь не перетаскивает узел B на узел A слишком быстро. Когда это происходит, методы контакта не всегда вызываются в правильное количество раз. Например, может быть обнаружено 3 контакта, но только два конечных контакта (или даже ни одного), что заставляет программу думать, что эти два узла по-прежнему перекрываются, даже если это не так. Я предполагаю, что это происходит потому, что пользователь перетаскивает узел быстрее, чем может обновить программа. Что я могу сделать, чтобы обойти это? В основном мне просто нужно точно знать, когда два узла перекрываются, а когда нет. Также обратите внимание, что узлы имеют выпуклую форму. Ниже приведены мои методы контакта:

func didBeginContact(contact: SKPhysicsContact)
{
    let contactMask = contact.bodyA.categoryBitMask + contact.bodyB.categoryBitMask

    if contactMask == 3
    {
        startContact++
        timerStart = true
    }
}

func didEndContact(contact: SKPhysicsContact)
{
    let contactMask = contact.bodyA.categoryBitMask + contact.bodyB.categoryBitMask

    if contactMask == 3
    {
        startContact--
        if startContact == 0
        {
            timerStart = false
        }
    }
} 

1 ответ

Вы можете проверить, пересекается ли один узел с другим, используя метод intersectsNode:. Из документов об этом методе:

Возвращает логическое значение, которое указывает, пересекает ли этот узел указанный узел.

Также важно помнить:

Считается, что два узла пересекаются, если их кадры пересекаются. Дочерние элементы обоих узлов игнорируются в этом тесте.

import SpriteKit

class GameScene: SKScene {


    var stationaryNode :SKSpriteNode = SKSpriteNode(color: SKColor.grayColor(), size: CGSize(width: 100, height: 100))

    var moveableNode   :SKSpriteNode = SKSpriteNode(color: SKColor.purpleColor(), size: CGSize(width: 100, height: 100))

    let debugLabel     :SKLabelNode  = SKLabelNode(fontNamed: "ArialMT")

    override func didMoveToView(view: SKView) {


        setupScene()

    }

    func setupScene(){

        stationaryNode.name = "stationaryNode"
        stationaryNode.zRotation = 0.2
        stationaryNode.zPosition = 1
        stationaryNode.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame))
        addChild(stationaryNode)

        moveableNode.name = "moveableNode"
        moveableNode.zRotation = 0.4
        moveableNode.zPosition = 2
        moveableNode.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame)-200)
        addChild(moveableNode)

        debugLabel.fontSize = 18
        debugLabel.fontColor = SKColor.yellowColor()
        debugLabel.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame)+200)
        addChild(debugLabel)
        updateDebugLabel()


    }

    func updateDebugLabel(){

        let intersectionDetected:String = stationaryNode.intersectsNode(moveableNode) ? "YES" : "NO"

        debugLabel.text = "Overlapping : " + intersectionDetected

    }

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {


        for touch in touches {

            let location = touch.locationInNode(self)

            let previousPosition = touch.previousLocationInNode(self)

            let node: SKNode? = nodeAtPoint(location)

            if let nodeName = node?.name{

                if nodeName == "moveableNode" {

                    let translation = CGPoint(x: location.x - previousPosition.x , y: location.y - previousPosition.y )

                    node!.position = CGPoint(x: node!.position.x + translation.x, y: node!.position.y + translation.y)

                }
            }

        }
    }

    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */


        updateDebugLabel()

    }
}

Я думаю, что это решение работает немного лучше, чем при использовании физического движка для обнаружения контактов для таких быстро движущихся объектов. Тем не менее, очень быстрое перемещение объекта может привести к непредсказуемому результату.

Другие вопросы по тегам