SceneKit SCNNode 跟随触摸移动

SceneKit SCNNode follow touch movement

我试图让球体节点仅在 x 轴上跟随我的手指在屏幕上的移动,而不影响球体的 y 或 z 值。我不确定我是否应该对物理体施加力或使用 SCNAction 移动它。球体将在占据屏幕宽度的立方体节点上弹跳。到目前为止,我最大的问题是弄清楚在 pangesture 函数中放入什么。这是我要复制的示例,其中用户在屏幕上滑动手指,球会反映其位置。

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

    for t in touches {

        let touchLocation = t.location(in: self.view)
        let touchCoordinatesX = (touchLocation.x - self.scnView.frame.width / 2)
        ballNode.position.x = Float(touchCoordinatesX/75)
    }
}

上面的代码有些工作,当我在屏幕上拖动我的手指时,y 位置会出现异常,并且上下滞后非常快,即使我的代码从未编辑球的 y 值。每次我在屏幕上拖动时,球的 y 位置都会重置为其添加到场景根节点时的原始值。

根据您的回答,这就是我所使用的并且完全符合我的需要。

@objc func handlePan(recognizer: UIPanGestureRecognizer)
{
    currentLocation = recognizer.location(in: self.view)

    let touchCoordinatesX = (currentLocation.x - self.scnView.frame.width / 2)



   if recognizer.state == .changed

   {

    ballNode.position.x = Float(touchCoordinatesX/75)
    ballNode.position.y = ballNode.presentation.position.y

    }

}

尝试 handlePan 和 setting/saving dragMode 状态变量。下面的代码是我用来 select 面板和扫视屏幕的东西,所以这些东西有一些额外的代码,但我认为你可以修改它以满足你的需要。在你的情况下,我的 "strafing the screen" 应该类似于你需要将球拖向你的指尖。

如果您在 dragChanges() 中将球对象设置为 currentLocation.x,那么它应该在您的指尖上准确对齐,并且响应应该会很快。根据您的图片,我的猜测是您需要稍微延迟一下,这样更逼真。如果是这种情况,我建议添加一个计时器并处理一个保存的 X 位置的小队列,以便它以小的增量到达您的指尖。

希望对您有所帮助。

//**************************************************************************
    @objc func handlePan(recognizer: UIPanGestureRecognizer)
    {
        currentLocation = recognizer.location(in: gameScene)
        let getLocation: CGPoint = recognizer.location(in: gameScene)
        let panHitTestResults = gameScene.hitTest(getLocation, options: hitTestOptions)

        if(data.gameState == .endWave || data.gameState == .endGame ||
            data.gameState == .defenseAdd || data.gameState == .defenseUpgrade)
        {
            dragMode = .none
            selectorActive = false
            lastPanelSelected = ""
            return
        }

        // State Begins
        if recognizer.state == UIGestureRecognizerState.began
        {
            dragMode = .drag
            beginLocation = recognizer.location(in: gameScene)
            data.panX = currentLocation.x
            data.lastMouseX = Float(beginLocation.x)
            data.lastMouseY = Float(beginLocation.y)
            dragBegins(vRecognizer: recognizer)
            selectorActive = false
        }
        // State Changes
        if(recognizer.state == UIGestureRecognizerState.changed)
        {
            dragChanges(vRecognizer: recognizer)

            if(data.gameState == .run && dragMode == .drag)
            {
                // If we were selecting cursor and want to cancel, just touch with 2 fingers
                if(recognizer.numberOfTouches == 2)
                {
                    dragMode = .none
                    selectorActive = false
                    grid.cancelCursor()
                    return
                }
                for vHit in panHitTestResults
                {
                    if(vHit.node.name?.prefix(5) == "Panel")
                    {
                        selectorActive = true
                        lastPanelSelected = vHit.node.name!
                        data.panelSelected = lastPanelSelected
                        let _ = grid.selectCursor()
                        return
                    }
                }
            }
        }

        if(recognizer.state == UIGestureRecognizerState.ended)
        {
            dragEnds(vRecognizer: recognizer)
            dragMode = .none

            if(selectorActive == true)
            {
                gameControl.selectPanel(vPanel: lastPanelSelected)
                lastPanelSelected = ""
                selectorActive = false
                return
            }
        }
    }
    //**************************************************************************
    func dragBegins(vRecognizer: UIPanGestureRecognizer)
    {
        if(data.gameState == .run)
        {
            if(vRecognizer.numberOfTouches == 2) { dragMode = .strafe }
        }
    }
    //**************************************************************************
    func dragChanges(vRecognizer: UIPanGestureRecognizer)
    {
        if(data.gameState == .run)
        {
            if(dragMode == .strafe && vRecognizer.numberOfTouches == 1)
            {
                dragMode = .none
                return
            }

            switch(dragMode)
            {
            case .strafe:
                gNodes.camera.strafe(vX: Float(currentLocation.x), vY: Float(currentLocation.y))
                break
            case .none:
                break
            default:
                break
            }
        }
    }
    //**************************************************************************
    func dragEnds(vRecognizer: UIPanGestureRecognizer)
    {
        if(data.gameState == .run)
        {
            switch(dragMode)
            {
            case .strafe:
                break
            default:
                break
            }
        }
        dragMode = .none
    }