【问题标题】:How to tap and move scene nodes in ARKit如何在 ARKit 中点击和移动场景节点
【发布时间】:2018-11-26 19:51:41
【问题描述】:

我目前正在尝试构建 AR Chess 应用程序,但无法让棋子的移动正常工作。

我希望能够点击一个棋子,然后它可以在棋盘上进行的合法移动将被突出显示,并且它将移动到用户点击的任何一个方格。

棋盘设计和节点的图片: https://gyazo.com/2a88f9cda3f127301ed9b4a44f8be047

我想实现的内容: https://imgur.com/a/IGhUDBW

非常感谢有关如何使其正常工作的任何建议。

谢谢!

ViewController 代码:

import UIKit
import SceneKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set the view's delegate
        sceneView.delegate = self

        // Show statistics such as fps and timing information
        sceneView.showsStatistics = true

        // Add lighting to the scene
        sceneView.autoenablesDefaultLighting = true
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // Create a session configuration to track an external image
        let configuration = ARImageTrackingConfiguration()

        // Image detection
        // Reference which group to find the image to detect in the Assets folder e.g. "Detection Card"
        if let imageDetect = ARReferenceImage.referenceImages(inGroupNamed: "Detection Card", bundle: Bundle.main) {
            // Sets image tracking properties to the image in the referenced group
            configuration.trackingImages = imageDetect
            // Amount of images to be tracked
            configuration.maximumNumberOfTrackedImages = 1
        }

        // Run the view's session
        sceneView.session.run(configuration)
    }

    // Run when horizontal surface is detected and display 3D object onto image
    // ARAnchor - tells a certain point in world space is relevant to your app, makes virtual content appear "attached" to some real-world point of interest
    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode {
        // Creates 3D object
        let obj = SCNNode()
        // Check if image detected through camera is an ARImageAnchor - which contains position and orientation data about the image detected in the session
        if let imageAnchor = anchor as? ARImageAnchor {
            // Set dimensions of the horizontal plane to be displayed onto the image to be the same as the image uploaded
            let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width, height: imageAnchor.referenceImage.physicalSize.height)
            // Display mild transparent layer onto detected image
            // This is to ensure image detection works by display a faint layer on the image
            plane.firstMaterial?.diffuse.contents = UIColor(white: 1.0, alpha: 0.2)
            // Set geometry shape of the plane
            let planeNode = SCNNode(geometry: plane)
            // Flip vertical plane to horizontal plane
            planeNode.eulerAngles.x = -Float.pi / 2
            obj.addChildNode(planeNode)

            // Initialise chess scene
            if let chessBoardSCN = SCNScene(named: "art.scnassets/chess.scn") {
                // If there is a first in the scene file
                if let chessNodes = chessBoardSCN.rootNode.childNodes.first {
                    // Displays chessboard upright
                    chessNodes.eulerAngles.x = Float.pi / 2
                    // Adds chessboard to the overall 3D scene
                    obj.addChildNode(chessNodes)
                }
            }

        }

        return obj

    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        // Pause the view's session
        sceneView.session.pause()
    }

}

【问题讨论】:

    标签: ios swift scenekit assets arkit


    【解决方案1】:

    您需要在视图中添加手势,并使用 ARSceneViews hitTest 方法来检测手势在场景中触摸的内容。然后,您可以根据手势的移动更新位置。

    这是一个处理大致相同的拖动节点要求的问题。

    Placing, Dragging and Removing SCNNodes in ARKit

    【讨论】:

    • 我已经添加了一个点击手势并在节点被点击时登录到控制台,但我现在遇到的问题是让它检测单个棋子而不是整个棋盘。我在我的帖子中链接了一张 gyazo 图像,说明我是如何构建我的作品和瓷砖的。你会如何建议我从这里对单个部件进行命中检测?提前致谢!感谢您抽出宝贵时间回复我的帖子
    • 您需要在每个 SCNNode 上放置某种类型的标识符,包括棋盘。当你做 hitTest 时,如果你检索一个节点,你可以检查这块的名称是什么,然后根据它进行相应的移动。 imo,您可能必须对 SCNNode 类进行子类化并添加一些属性,例如它的当前棋盘位置、棋子类型等……这可能有助于简化识别。同样在另一个问题中,我只是通过检查节点的名称来完成它。另外,没问题。 AR 对我来说也很难学习,有时很难获得帮助。
    【解决方案2】:

    首先,您需要在 viewDidLoad 中添加一个手势识别器,如下所示:

     let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
     myScnView.addGestureRecognizer(tapGesture)
    

    然后实现handler函数:

        @objc
        func handleTap(_ gestureRecognize: UIGestureRecognizer) {
           // HERE YOU NEED TO DETECT THE TAP
           // check what nodes are tapped
    
            let location = gestureRecognize.location(in: myScnView)
            let hitResults = myScnView.hitTest(location, options: [:])
    
            // check that we clicked on at least one object
            if hitResults.count > 0 {
                // retrieved the first clicked object
                let tappedPiece = hitResults[0].node
    
                // HERE YOU CAN SHOW POSSIBLE MOVES
                //Ex. showPossibleMoves(for: tappedPiece) 
            }
    
        }
    

    现在,要显示可能的走法,您需要确定棋盘上的所有象限和节点位置

    为此,您可以指定名称或数字,或字母和数字的组合,或者数字的组合。 (我建议组合数字,如第 1 行第 1 列,如矩阵)。

    让我们接受我的建议,因此您可以将每个象限命名为 1.1 1.2 ... 2.1 2.2 等等。

    现在,要检测您的作品在哪里,您可以检查与 PhysicsContactDelegate 的联系。

    现在你已经有了 tappedPiece 和它所在的位置,所以你必须定义碎片的规则,例如:

    let rules = ["tower":"cross"] //add the others
    

    注意您可以选择要定义的规则。

    让我们接受我的建议,现在您应该创建要突出显示的函数:

     func highlight(quadrant: SCNNode){
       quadrant.geometry?.firstMaterial?.emission.contents = UIColor.yellow
     }
    

    最后 showPossibleMoves(for: tappedPiece) 可能是这样的:

    func showPossibleMoves(for piece: SCNNode){
    
    let pieceType = piece.name //You have to give the name as you did into your rules variable
     //ex. if you have rules like ["tower":"cross"] you have to set all towers name to "tower"
    
    let rule = rules[pieceType]
    
    switch rule{
    
    case "cross":
    
          //you have to highlight all nodes on the right, left, above and bottom
          // you can achieve this by selecting the start point and increase it
          //assuming you named your quadrants like 1.1 1.2 or 11 12 13 ecc...
          let startRow = Int(startQuadrant.name.first)
          let startColumn = Int(startQuadrant.name.last)
    
          //Now loop the highlight on right
          for column in startColumn+1...MAX_COLUMN-1{
             let quadrant = myScnView.scene.rootNode.childNode(withName:"\(startRow).\(column)" , recursively: true)
             // call highlight function
              highlight(quadrant: quadrant)
          }
    
          //Now loop for above quadrants
          for row in startRow+1...MAX_ROW-1{
             let quadrant = myScnView.scene.rootNode.childNode(withName:"\(row).\(startColumn)" , recursively: true)
             // call highlight function
              highlight(quadrant: quadrant)
          }
    
          //DO THE SAME FOR ALL DIRECTIONS
    }
    
    // ADD ALL CASES, like bishop movements "diagonals" and so on
    
    }
    

    注意:在 handlerTap 函数中,您必须检查您正在点击的内容,例如,在选择一块后检查您是否正在点击象限(你想移动你的一块)你可以检查一个布尔值和所选节点的名称

      //assuming you have set the boolean value after selecting a piece
    
      if pieceSelected && node.name != "tower"{
    
          //HERE YOU CAN MOVE YOUR PIECE
    
      }
    

    【讨论】:

    • 您好,首先非常感谢您的彻底回复,我很感激您在回复中写下所有内容可能需要一段时间。我还有几个问题:我正在考虑将象限作为官方国际象棋规则中方格的名称来实现,例如A1 或 H8 ...但我无法通过定义规则来理解您的意思,例如"let rules = ["tower":"cross"]" - 我对方括号中的符号不​​是很熟悉,这是什么意思?
    • 另外,如果您到目前为止查看了我项目的 gyazo 快照,但我已经将每个瓷砖和一块单独命名为它开始的相应正方形,每块和瓷砖都是我转换的 3d 模型并作为 .scn 文件导入到我的项目中,以便我可以在我的项目中使用它。你会建议我如何操纵并将对象链接到我的代码,因为我认为这是我真正难以掌握的概念。
    • 很抱歉打扰了您,但我花了一整天的时间试图弄清楚如何移动棋子,但到目前为止我一无所获。
    • 您好,很遗憾我没有太多时间,但请不要抱歉。这 -> "let rules = ["tower":"cross"]" 是一个字典(或 HashMap)的一个键值数据结构。我建议它仅用于切换规则大小写,但您可以通过逐条切换规则来避免这种情况。对于您的第二条评论,我不明白您的意思?如果需要将 3D 模型链接到变量,可以使用 sceneView.scene.rootNode.childWithName。通过使用 A1 ecc .. 逻辑和我说的一样。但是,如果你有 quadrant 和 piece,你可以使用 SCNAction 让 piece 做一个动作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-30
    • 2016-04-22
    • 2016-12-12
    • 2015-02-03
    • 2015-04-28
    • 2023-03-12
    相关资源
    最近更新 更多