SceneKit перетаскивание для узла стрелки с увеличением размера хвоста - PullRequest
0 голосов
/ 08 мая 2020

Проблема

Я разрабатываю функцию перетаскивания стрелки, чтобы растянуть ее, и столкнулся со следующими проблемами:

  1. Как рассчитать поворот для узла стрелки, чтобы после перетаскивания острие стрелки смотрит на конечную позицию касания?
  2. Как преобразовать movementVector из начальной в конечную позицию для расчета масштаба хвоста?

Описание

В моем случае arrowNode содержит 2 узла: head и tail .

movementVector - 3D-вектор, содержащий разницу по расстоянию между концом и началом движения.

Опорная точка хвост сместилась к правой границе, так что, изменяя масштаб X , мы увеличиваем длина хвоста.

Xcode игровая площадка

Код

    func createArrowNode() -> SCNNode {
       let arrowNode = SCNNode()
       arrowNode.name = "arrow"

       let tail = SCNPlane(width: 3, height: 2)
       let tailNode = SCNNode(geometry: tail)
       tailNode.name = "tail"
       tailNode.position = SCNVector3(0.25, 0, 0)
       // Move pivot to the edge of the tail
       tailNode.pivot = SCNMatrix4MakeTranslation(Float(tail.width / 2), 0, 0)
       tailNode.renderingOrder = 2

       let head = SCNPlane(width: 5.2, height: 5.2)
       let headNode = SCNNode(geometry: head)
       headNode.name = "head"
       headNode.renderingOrder = 1

       arrowNode.addChildNode(tailNode)
       arrowNode.addChildNode(headNode)
       return arrowNode
    }

 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let sceneView = view as? SCNView,
            let touchLocation = touches.first?.location(in: sceneView) else { return }

        let hitTestOptions: [SCNHitTestOption : Any] = [
            .boundingBoxOnly: true,
        ]

        guard var node = sceneView.hitTest(touchLocation, options: hitTestOptions).first?.node else { return }
        // use arrow node container
        node = node.name == "tail" || node.name == "head"
            ? node.parent!
            : node

        lastTouchPosition = node.worldPosition
        touchedNode = node
        touchStartZ = CGFloat(sceneView.projectPoint(lastTouchPosition!).z)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let sceneView = view as? SCNView,
            let touchLocation = touches.first?.location(in: sceneView) else { return }

        guard let previousPosition = lastTouchPosition,
            let touchStartZ = touchStartZ,
            let touchedNode = touchedNode else { return }

        let current3DPosition = SCNVector3(touchLocation.x, touchLocation.y, touchStartZ)
        let worldTouchPosition = sceneView.unprojectPoint(current3DPosition)

        lastTouchPosition = worldTouchPosition

        let movementVector = worldTouchPosition - previousPosition
        changeArrow(movementVector: movementVector, arrowNode: touchedNode )
    }

image

Спасибо!

...