Как нажимать и перемещать узлы сцены в ARKit - PullRequest
0 голосов
/ 26 ноября 2018

В настоящее время я пытаюсь создать приложение 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()
    }

}

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Во-первых, вам нужно добавить распознаватель жестов для касания в ваш viewDidLoad, например:

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

Затем реализуйте функцию обработчика:

    @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

NB Вы можете выбрать, что вы хотите определить правила.

Давайте хорошо примем мое предложение,теперь вы должны создать функцию для выделения:

 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

  }
0 голосов
/ 26 ноября 2018

Вам нужно будет добавить жесты к вашему виду и использовать метод hitTest ARSceneViews, чтобы определить, к какому жесту относится ваша сцена.Затем вы можете обновить позиции на основе движения от жестов.

Вот вопрос, который касается примерно того же требования перетаскивания узлов вокруг.

Размещение, перетаскивание и удаление узлов SCN в ARKit

...