【问题标题】:swift SceneKit decline node moveswift SceneKit 拒绝节点移动
【发布时间】:2021-08-25 12:08:55
【问题描述】:

我创建了一个球体节点,我需要用户只能旋转(左/右,上/下)和放大/缩小节点,但默认他可以从中心移动节点(用两根手指) - 是否可以禁止用户从中心移动节点?感谢您的帮助

sceneView.scene = scene

cameraOrbit = SCNNode()
cameraNode = SCNNode()
camera = SCNCamera()

// camera stuff
camera.usesOrthographicProjection = true
camera.orthographicScale = 5
camera.zNear = 1
camera.zFar = 100

cameraNode.position = SCNVector3(x: 0, y: 0, z: 70)
cameraNode.camera = camera
cameraOrbit = SCNNode()
cameraOrbit.addChildNode(cameraNode)
scene.rootNode.addChildNode(cameraNode)

let sphere = SCNSphere(radius: 2)
sphere.firstMaterial?.diffuse.contents = UIColor.red
let earthNode = SCNNode(geometry: sphere)
earthNode.name = "sphere"
earthNode.geometry?.materials = [blueMaterial]
scene.rootNode.addChildNode(earthNode)
earthNode.rotation = SCNVector4(0, 1, 0, 0)

let lightNode = SCNNode()
let light = SCNLight()
light.type = .ambient
light.intensity = 200
lightNode.light = light
scene.rootNode.addChildNode(lightNode)

sceneView.allowsCameraControl = true
sceneView.backgroundColor = UIColor.clear
sceneView.cameraControlConfiguration.allowsTranslation = true
sceneView.cameraControlConfiguration.rotationSensitivity = 0.4

【问题讨论】:

    标签: swift scenekit


    【解决方案1】:

    您可以将类似的代码放入您的 UIViewController:

    //**************************************************************************
        // Gesture Recognizers
        // MARK: Gesture Recognizers
        //**************************************************************************
        @objc func handleTap(recognizer: UITapGestureRecognizer)
        {
            if(data.isNavigationOff == true) { return }         // No panel select if Add, Update, EndWave, or EndGame
            if(gameMenuTableView.isHidden == false) { return }  // No panel if game menu is showing
            
            let location: CGPoint = recognizer.location(in: gameScene)
            
            if(data.isAirStrikeModeOn == true)
            {
                let projectedPoint = gameScene.projectPoint(SCNVector3(0, 0, 0))
                let scenePoint = gameScene.unprojectPoint(SCNVector3(location.x, location.y, CGFloat(projectedPoint.z)))
                gameControl.airStrike(position: scenePoint)
            }
            else
            {
                let hitResults = gameScene.hitTest(location, options: hitTestOptions)
                for vHit in hitResults
                {
                    if(vHit.node.name?.prefix(5) == "Panel")
                    {
                        // May have selected an invalid panel or auto upgrade was on
                        if(gameControl.selectPanel(vPanel: vHit.node.name!) == false) { return }
                        return
                    }
                }
            }
        }
        //**************************************************************************
        @objc func handlePan(recognizer: UIPanGestureRecognizer)
        {
            if(data.gameState != .run || data.isGamePaused == true) { return }
            
            currentLocation = recognizer.location(in: gameScene)
            
            switch recognizer.state
            {
            case UIGestureRecognizer.State.began:
                beginLocation = recognizer.location(in: gameScene)
                break
            case UIGestureRecognizer.State.changed:
                if(currentLocation.x > beginLocation.x * 1.1)
                {
                    beginLocation.x = currentLocation.x
                    gNodes.camera.strafeLeft()
                }
                if(currentLocation.x < beginLocation.x * 0.9)
                {
                    beginLocation.x = currentLocation.x
                    gNodes.camera.strafeRight()
                }
                break
            case UIGestureRecognizer.State.ended:
                break
            default:
                break
            }
        }
    

    【讨论】:

      【解决方案2】:

      是的,所有这些都是可行的。首先,创建自己的相机类并关闭allowsCameraControl。然后你可以实现缩放/扫射/任何东西。

      这里有一些示例可能会有所帮助,只需在堆栈搜索栏中搜索这些数字并找到我的答案/示例即可。

      57018359 - 这篇文章告诉您如何触摸 2d 屏幕(点击)并将其转换为 3d 坐标,由您决定深度 (z),就像您想点击屏幕并将对象放置在 3d 空间中一样。

      57003908 - 这篇文章告诉您如何使用 hitTest(点击)选择对象。例如,如果您显示带有门的房屋正面并点击它,那么该函数将返回您的门节点,前提是您将节点命名为“门”并在它被触摸时采取某种行动。然后您可以根据该位置重新定位您的相机。您需要遍历所有结果,因为可能存在重叠或加上 Z 节点

      55129224 - 这篇文章为您提供了创建相机类的快速示例。您可以使用它来重新定位相机或前后移动相机等。

      两指拖动:

      func dragBegins(vRecognizer: UIPanGestureRecognizer)
          {
              if(data.gameState == .run)
              {
                  if(vRecognizer.numberOfTouches == 2) { dragMode = .strafe }
              }
          }
      
      
      class Camera
      {
          var data = Data.sharedInstance
          var util = Util.sharedInstance
          var gameDefaults = Defaults()
          
          var cameraEye = SCNNode()
          var cameraFocus = SCNNode()
          
          var centerX: Int = 100
          var strafeDelta: Float = 0.8
          var zoomLevel: Int = 35
          var zoomLevelMax: Int = 35              // Max number of zoom levels
          
          //********************************************************************
          init()
          {
              cameraEye.name = "Camera Eye"
              cameraFocus.name = "Camera Focus"
              
              cameraFocus.isHidden = true
              cameraFocus.position  =  SCNVector3(x: 0, y: 0, z: 0)
              
              cameraEye.camera = SCNCamera()
              cameraEye.constraints = []
              cameraEye.position = SCNVector3(x: 0, y: 15, z: 0.1)
              
              let vConstraint = SCNLookAtConstraint(target: cameraFocus)
              vConstraint.isGimbalLockEnabled = true
              cameraEye.constraints = [vConstraint]
          }
          //********************************************************************
          func reset()
          {
              centerX = 100
              cameraFocus.position  =  SCNVector3(x: 0, y: 0, z: 0)
              cameraEye.constraints = []
              cameraEye.position = SCNVector3(x: 0, y: 32, z: 0.1)
              cameraFocus.position = SCNVector3Make(0, 0, 0)
              
              let vConstraint = SCNLookAtConstraint(target: cameraFocus)
              vConstraint.isGimbalLockEnabled = true
              cameraEye.constraints = [vConstraint]
          }
          //********************************************************************
          func strafeRight()
          {
              if(centerX + 1 < 112)
              {
                  centerX += 1
                  cameraEye.position.x += strafeDelta
                  cameraFocus.position.x += strafeDelta
              }
          }
          //********************************************************************
          func strafeLeft()
          {
              if(centerX - 1 > 90)
              {
                  centerX -= 1
                  cameraEye.position.x -= strafeDelta
                  cameraFocus.position.x -= strafeDelta
              }
          }
          //********************************************************************
      }
      
      
      //********************************************************************
          func lerp(start: SCNVector3, end: SCNVector3, percent: Float) -> SCNVector3
          {
              let v3 = cgVecSub(v1: end, v2: start)
              let v4 = cgVecScalarMult(v: v3, s: percent)
              return cgVecAdd(v1: start, v2: v4)
          }
      

      【讨论】:

      • 感谢您的回答!你有例子如何实现左、下、缩放等方法吗?
      • 我在这个相机类中有扫射,但缩放只是将相机放置在更靠近节点的位置。我通常会设置一个缩放级别,然后在需要时获得默认距离和一个 lerp。但通常情况下,您会有一些理想的距离,只需对其进行一些基本的矢量数学运算即可。
      • 我为你添加了一个 lerp 示例。
      • 非常感谢。如果对你来说不难,你能解释一下如何检查用户是否正在转动节点、放大等吗?不知道如何判断用户是否开始旋转节点,例如需要调用 strafeLeft 方法
      猜你喜欢
      • 2021-10-11
      • 1970-01-01
      • 2017-12-25
      • 2018-02-09
      • 2014-11-24
      • 1970-01-01
      • 1970-01-01
      • 2021-08-24
      • 2016-09-15
      相关资源
      最近更新 更多