如何将结构或 class 对象附加到 SCNNode

How to attach a struct or class object to a SCNNode

我正在尝试创建一个场景,让不同的用户可以展示不同的汽车。当用户首次登录到应用程序时,他们会获得 uid、用户名等。当他们选择汽车时,汽车模型具有汽车类型和标识他们的用户对象。

我可以创建一辆汽车并实施 hitTest 来查找哪辆汽车被点击了。我想不通的是如何为被窃听的汽车分配数据模型,以便我知道谁是谁?

到目前为止,我在节点上发现的唯一 属性 是 node.name,我可以将 userId 附加到它,然后通过一组用户来找出谁是谁,但事实并非如此;如果我有很多用户,这似乎很实用。删除节点时我还需要 属性:

sceneView.session.pause()
sceneView.scene.rootNode.enumerateChildNodes { (node, _) in
    // this would actually remove all the ferraries on the scene but this is just an example
    if node.name == "ferrari" {
        node.removeFromParentNode()
    }
}

如何将数据模型附加到 SCNNode?

class User {
    var userId: String?
    var username: String?
}

class RaceCar {
    var user: User?
    var type: String?
}

// user creates an account and picks a ferrari

let raceCar = RaceCar()
let type = raceCar.type!

switch type {

    case "ferrari":

        createFerrariAndAddItToScene(raceCar)

    case "bmw":
    ...etc
}

func createFerrariAndAddItToScene(_ raceCar: RaceCar) {

      let image = art.scnassests/"\(raceCar.typ!e).jpg"

      let material = SCNMaterial()
      material.diffuse.contents = image

      let plane = SCNPlane(width: 0.1, height: 0.1)
      plane.materials = [material]

      let node = SCNNode()
      node.name = raceCar.type!
      node.geometry = plane
      node.position = SCNVector(0.0, 0.0, -0.2)

      sceneView.scene.rootNode.addChildNode(node)
}

@objc func nodeWasTapped(_ sender: UITapGestureRecognizer) {

    guard let sceneView = sender.view as? ARSCNView else { return }  
    let touchLocation = sender.location(in: sceneView)

    let hitResults = sceneView.hitTest(touchLocation, options: [:])

    if !hitResults.isEmpty {

        guard let hitResult = hitResults.first  else { return }  
        let node = hitResult.node

        print(node.name) // I need to get some info from the dataModel here like node.raceCar.user.username or node.raceCar.user.userId
    }
}

您可以子class SCNNode 并向其中添加您需要的任何数据模型:

class CarNode: SCNNode {
  var raceCar: RaceCar?

  init(raceCar: RaceCar, geometry: SCNGeometry) {
    super.init()

    self.geometry = geometry

    self.raceCar = raceCar
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
}

要创建新节点,只需使用这个新的 class:

func createFerrariAndAddItToScene(_ raceCar: RaceCar) {
  ...
  let node = CarNode(raceCar: raceCar, geometry: plane)
  ...
}

要访问您的数据模型,您可以这样做:

@objc func nodeWasTapped(_ sender: UITapGestureRecognizer) {
  ...
  if let node = hitResult.node as? CarNode {
    print(node.raceCar.user.username)
  }
}

我运气不错 setValue:ForKey:

node.setValue(tile, forKey: "tile")

...

if let tile = node.value(forKey: "tile") as? Tile {
    ...
}