So I asked a question a couple of days ago which Andy Jazz kindly answered. So I have been playing with the answer, and although I was able to implement a solution, it is incomplete because the method he used, was findEntity(named:)
using RealityKit. While I used Reality Composer on my own answer.
Problem #1: findEntity(named:)
method doesn't work on Reality Composer when you have multiple objects. So I arrived at the realization the using the findEntity(named:) method doesn't work. Because all the objects within the scene are named "simpBld_root"
, it doesn't work to trigger what I want to trigger.
Problem #2: When using the parenting notation, I am doing a trial and error because I don't really understand what is what. How can I call each object? This is also a consequence of my own inability to correctly understand WHAT to call from Reality Composer because I don't think I really understand how the parenting notation applies in reality composer. The picture below is the Scene I am working printed on the console.
Below is an example I made work, where instead of Andy's solution for findEntity(named: ) I used children[0]
This is the code I tried, when using the findEntity() method that did NOT work:
let redBoardModelEntity = cubesAnchor.redBoard?.findEntity(named: "simpBld_root") as! ModelEntity
let greenCubeModelEntity = cubesAnchor.greenCube?.findEntity(named: "simpBld_root") as! ModelEntity
let blueCubeModelEntity = cubesAnchor.blueCube?.findEntity(named: "simpBld_root") as! ModelEntity
And this is what I ended up with, that worked, meaning, it showed all the objects and the entire thing dragged together. [See pic below, followed by code]
import UIKit
import RealityKit
class ViewController: UIViewController {
@IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
let boxAnchor = try! Experience.loadBox()
arView.scene.anchors.append(boxAnchor)
let cubesAnchor = try! Experience.loadCubes()
arView.scene.anchors.append(cubesAnchor)
print (cubesAnchor)
cubesAnchor.actions.behavior.onAction = handleTapOnEntity(_:)
let redModel = cubesAnchor.children[0].children[0]
let group = ModelEntity() as ModelEntity & HasCollision
group.addChild(redModel)
// group.addChild(blueCubeModelEntity)
// group.addChild(greenCubeModelEntity)
group.generateCollisionShapes(recursive: false)
self.arView.installGestures(.all, for: group)
let shape = ShapeResource.generateBox(width: 1, height: 1, depth: 1)
let collision = CollisionComponent(shapes: [shape],
mode: .trigger,
filter: .sensor)
group.components.set(collision)
let anchor = AnchorEntity()
anchor.addChild(group)
anchor.scale = [5,5,5]
arView.scene.anchors.append(anchor)
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0){
// self.arView.scene.anchors.removeAll()
let coneAnchor = try! Experience.loadCone()
self.arView.scene.anchors.append(coneAnchor)
coneAnchor.actions.behavior.onAction = handleTapOnEntity(_:)
// print(cubesAnchor)
}
boxAnchor.actions.behavior.onAction = handleTapOnEntity(_:)
func handleTapOnEntity(_ entity: Entity?){
guard let entity = entity else { return }
// self.myEntity = entity
// self.myEntity?.isEnabled = false
}
}
}
According to diagram, your models are called greenCube
, redBoard
and blueCube
respectively. Thus, the simplest way to get any ModelEntity from Reality Composer's scene hierarchy is to apply findEntity(named:)
method followed by access to its sub-children.
let model = cubesAnchor.findEntity(named: "greenCube")?.children[0] as! ModelEntity
...or, thanks to the Reality Composer's naming scheme:
let model = cubesAnchor.greenCube?.children[0] as! ModelEntity
Names greenCube
, redBoard
and blueCube
are entities' names. All three models have a name simpBld_root
. So, you can rename each ModelEntity if you like.
model.name = "Green_Cube_Model"
print(cubesAnchor.findEntity(named: "greenCube")!)
Result in Xcode's console:
▿ 'greenCube' : Entity, children: 1
⟐ Transform
⟐ SynchronizationComponent
▿ 'Green_Cube_Model' : ModelEntity // New name
⟐ PhysicsBodyComponent
⟐ Transform
⟐ SynchronizationComponent
⟐ CollisionComponent
⟐ ModelComponent
Now you are able to get each ModelEntity via its unique name:
let green = cubesAnchor.findEntity(named: "Green_Cube_Model") as! ModelEntity
Or you can go through the chain of children.
Here's my code:
import UIKit
import RealityKit
class ViewController: UIViewController {
@IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
let scene = try! Experience.loadTwoBoxes()
// MODEL 001
let model001 = scene.findEntity(named: "redCube")?.children[0] as! ModelEntity & HasPhysicsBody
model001.position.y = 1.0
model001.physicsBody = .init()
model001.generateCollisionShapes(recursive: false)
// MODEL 002
let forRenaming: Entity = scene.findEntity(named: "blueCube")!
forRenaming.children[0].name = "Blue_Cube_Model"
print(forRenaming)
let model002 = scene.findEntity(named: "Blue_Cube_Model") as! ModelEntity & HasPhysicsBody
model002.position.y = 1.0
model002.physicsBody = .init()
model002.generateCollisionShapes(recursive: false)
arView.scene.anchors.append(scene)
}
}