SKPhysicsJoint заставляет вращение работать неправильно

Используя Swift и Sprite-Kit, я пытаюсь создать веревку с реалистичной физикой между местоположением статического SKSpriteNode, называемого контактным, и везде, где пользователь касается экрана. Я делаю это, добавляя отдельные узлы SKSpriteNodes, называемые узлами веревки, и связывая их с серией контактов SKPhysicsJointPins. Физика работает просто отлично, однако, когда я пытаюсь повернуть каждую отдельную часть так, чтобы они были правильно ориентированы, узлы веревки больше не образуют прямую линию и не поворачиваются под правильным углом. Однако когда я удаляю SKPhysicsJoints, вращение работает так, как задумано для каждого отдельного узла. Перемещение по якорной точке для каждого отдельного узла веревки только усугубляло путаницу. Почему это происходит, и как я могу это исправить? Заранее спасибо (:

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    /* Called when a touch begins */
    
    for touch in (touches as! Set<UITouch>) {
        let location = touch.locationInNode(self)
        dx = pin.position.x - location.x
        dy = pin.position.y - location.y
        let length = sqrt(pow(dx!, 2) + pow(dy!, 2))
        let distanceBetweenRopeNodes = 40
        let numberOfPieces = Int(length)/distanceBetweenRopeNodes
        var ropeNodes = [SKSpriteNode]()
        
        //adds the pieces to the array and the scene at respective locations
        for var index = 0; index < numberOfPieces; ++index{
            let point = CGPoint(x: pin.position.x + CGFloat((index) * distanceBetweenRopeNodes) * sin(atan2(dy!, -dx!) + 1.5707), y: pin.position.y + CGFloat((index) * distanceBetweenRopeNodes) * cos(atan2(dy!, -dx!) + 1.5707))
            let piece = createRopeNode(point)
            piece.runAction(SKAction.rotateByAngle(atan2(-dx!, dy!), duration: 0))
            ropeNodes.append(piece)
            self.addChild(ropeNodes[index])
        }

        //Adds an SKPhysicsJointPin between each pair of ropeNodes
        self.physicsWorld.addJoint(SKPhysicsJointPin.jointWithBodyA(ropeNodes[0].physicsBody, bodyB: pin.physicsBody, anchor:
            CGPoint(x: (ropeNodes[0].position.x + pin.position.x)/2, y: (ropeNodes[0].position.y + pin.position.y)/2)))
        for var i = 1; i < ropeNodes.count; ++i{
            let nodeA = ropeNodes[i - 1]
            let nodeB = ropeNodes[i]
            let middlePoint = CGPoint(x: (nodeA.position.x + nodeB.position.x)/2, y: (nodeA.position.y + nodeB.position.y)/2)
            let joint = SKPhysicsJointPin.jointWithBodyA(nodeA.physicsBody, bodyB: nodeB.physicsBody, anchor: middlePoint)
            self.physicsWorld.addJoint(joint)
        }
    }
}

func createRopeNode(location: CGPoint) -> SKSpriteNode{
    let ropeNode = SKSpriteNode(imageNamed: "RopeTexture")
    ropeNode.physicsBody = SKPhysicsBody(rectangleOfSize: ropeNode.size)
    ropeNode.physicsBody?.affectedByGravity = false
    ropeNode.physicsBody?.collisionBitMask = 0
    ropeNode.position = location
    ropeNode.name = "RopePiece"
    return ropeNode
}

Это изображение того, что происходит, когда я пытаюсь вращать каждый отдельный узел веревки.

введите здесь описание изображения


person Lahav    schedule 15.08.2015    source источник
comment
Возможно, вам потребуется добавить узел представления к каждому из сегментов веревки. Узел представления — это визуальное представление другого узла, которое вы можете изменить (например, повернуть), не влияя на физику фактического узла.   -  person 0x141E    schedule 15.08.2015
comment
То есть в основном добавлять узлы без физического тела и только с текстурой вместо существующих узлов веревки?   -  person Lahav    schedule 15.08.2015
comment
Да, и установите их позиции такими же, как у сегментов веревки в didSimulatePhysics, и сделайте узел веревки с телом невидимым.   -  person 0x141E    schedule 15.08.2015
comment
Это может сработать, однако для этого потребуется, чтобы я продолжал перемещать текстуры в их правильное положение в каждом кадре, поскольку на самом деле у них нет никакой физики. Это было бы очень неэффективно   -  person Lahav    schedule 15.08.2015
comment
Другой способ сделать это — добавить дочерний узел, который вращается, но вам нужно будет противодействовать вращению родителя, а затем повернуть дочерний узел на нужный угол.   -  person 0x141E    schedule 15.08.2015
comment
Установка позиций узлов выполняется очень быстро. Я бы удивился, если бы это вообще повлияло на вашу игру.   -  person 0x141E    schedule 15.08.2015
comment
На самом деле вы делаете хорошее замечание   -  person Lahav    schedule 16.08.2015


Ответы (1)


После некоторых размышлений я думаю, что добавление узла представления в качестве дочернего — лучшая идея, поскольку вам не нужно отслеживать дополнительные узлы в отдельном массиве. Чтобы установить вращение дочернего элемента, просто отмените вращение родителя, а затем добавьте новый угол поворота:

node.zRotation = -node.parent!.zRotation + newRotation

Если сегменты веревки находятся в контейнере SKNode, вы можете выполнить итерацию по ним,

for rope in ropes.children {
    if let node = rope.children.first {
        let newRotation = ...
        node.zRotation = -rope.zRotation + newRotation
    }
}
person 0x141E    schedule 16.08.2015
comment
Я в основном сделал то, что вы сделали. Я только что добавил let text = SKSpriteNode(imageNamed: "RopeTexture") text.runAction(SKAction.rotateByAngle(atan2(-dx!, dy!), duration: 0)) ropeNode.addChild(text) в свой метод createRopeNode(). - person Lahav; 16.08.2015