I'm trying to create a scene where different users can display different cars. When the user first signs into the app they get uid, username etc. When they choose a car the car model has the type of car and a user object that identifies them.
I can create a car and implement the hitTest to find which car was tapped. What I can't figure out is how do I assign a data model to the car that was tapped so that I know who's who?
The only property I found on the node so far is the node.name
, I can attach the userId to it and just go through an array of users to find out who's who but that doesn;t seem practical if I have a lot of users. I also need that property when removing a node:
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()
}
}
How can I attach a data model to a 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
}
}
You can subclass SCNNode
and add any data model you need to it:
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")
}
}
To create new node simply use this new class:
func createFerrariAndAddItToScene(_ raceCar: RaceCar) {
...
let node = CarNode(raceCar: raceCar, geometry: plane)
...
}
To access your data model you can do like so:
@objc func nodeWasTapped(_ sender: UITapGestureRecognizer) {
...
if let node = hitResult.node as? CarNode {
print(node.raceCar.user.username)
}
}