【问题标题】:SceneKit SCNNode follow touch movementSceneKit SCNNode 跟随触摸移动
【发布时间】:2019-04-14 18:46:15
【问题描述】:

我试图让一个 Sphere 节点跟随我的手指在屏幕上的移动仅在它的 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

    }

}

【问题讨论】:

    标签: ios swift4 uigesturerecognizer scenekit uipangesturerecognizer


    【解决方案1】:

    尝试使用 handlePan 并设置/保存一个 dragMode 状态变量。下面的代码是我用来选择面板并扫视屏幕的代码,因此有一些额外的代码用于这些内容,但我认为您可以对其进行修改以满足您的需要。在您的情况下,我的“扫射屏幕”应该类似于您将球拖向指尖的需要。

    如果你在 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
        }
    

    【讨论】:

    • 这对我帮助很大,谢谢。我应该在 handlePan 函数中放置什么来防止用户移动球,除非它在距离球的 x 范围内?如果我在屏幕的最右侧平移,并且球位于最左侧,它会“传送”到手势位置。我不希望它那样做。
    • 我想我会尝试计时器路线。放置一个计时器,以便 position.x 仅在计时器关闭时设置。那么它应该减少“传送”的影响。将最后一个 X(在我的 data.lastMouseX 中)值保存在可以在计时器之间共享并调用它的地方。
    • 您也可以使用 lerp 在 x 和最右侧平移拖动之间获得几个点
    猜你喜欢
    • 2016-09-15
    • 1970-01-01
    • 1970-01-01
    • 2015-09-05
    • 2015-06-07
    • 1970-01-01
    • 2017-08-31
    • 1970-01-01
    • 2017-08-28
    相关资源
    最近更新 更多