Im trying to create a functionality in ARKit where if the user taps on the modelEntity it changes its colour to lets say blue so it indicates that it's selected. But then if the user taps on another entity, the previously selected entity's material changes back to what it was before it was selected.
So i am able to change its colour with this code:
let selectedMaterial = SimpleMaterial(color: .link, isMetallic: false)
selectedEntity.model?.materials[0] = selectedMaterial
But how do I change it back after I 'deselect' it, when i select another modelEntity?
Because I've been trying to save it's material to a variable, but I'm having a problem with it, because lets say there are two modelEntites, A and B. When I tap the "A" entity it changes colour, then I tap on the "B" entity then "B" entity's colour changes and the "A" entity's material changes back to the original (like how it should be working), but when I tap again on the "A" entity the "B" entity's material goes back to the original but the "A" entity's colour doesn't change.
This is how I'm trying to make it work:
enum EntityState {
case unselected
case selected
case correctName
case wrongName
}
private var entitiesState: [String: EntityState] = [String: EntityState]()
private var modelEntities: [ModelEntity] = [ModelEntity]()
private var modelEntitiesMaterials: [String: [Material]] = [String: [Material]]()
//This is how i place a modelEntity
@objc private func placeObject() {
let modelName = self.model.name ?? ""
let entity = try! Entity.load(named: modelName)
let geomChildrens = entity.findEntity(named: "Geom")
if let geomChildrens = geomChildrens {
for children in geomChildrens.children {
let childModelEntity = children as! ModelEntity
childModelEntity.collision = CollisionComponent(shapes: [ShapeResource.generateConvex(from: childModelEntity.model!.mesh)])
entitiesState[childModelEntity.name] = EntityState.unselected
modelEntities.append(childModelEntity)
}
}
let modelEntity = ModelEntity()
modelEntity.addChild(entity)
let anchorEntity = AnchorEntity(.plane(.horizontal, classification: .any, minimumBounds: .zero))
anchorEntity.addChild(modelEntity)
arView.installGestures([.all],for: modelEntity)
arView.scene.addAnchor(anchorEntity)
}
private func selectEntity(withSelectedEntity: ModelEntity?) {
modelInformationView.isHidden = false
//If we didnt hit any modelEntity
guard let selectedEntity = withSelectedEntity else {
//Unselect the selected entity if there is one.
for entity in modelEntities {
if(entitiesState[entity.name] == .selected) {
entitiesState[entity.name] = .unselected
}
}
colorModelEntities()
return
}
if(entitiesState[selectedEntity.name] == .selected) {
// If its already selected, just unselect
entitiesState[selectedEntity.name] = .unselected
} else {
//First unselect the previously selected entity.
for entity in modelEntities {
if(entitiesState[entity.name] == .selected) {
entitiesState[entity.name] = .unselected
}
}
//Select the entity.
entitiesState[selectedEntity.name] = .selected
}
colorModelEntities()
}
private func colorModelEntities() {
let selectedMaterial = SimpleMaterial(color: .link, isMetallic: false) //Blue
for entity in modelEntities {
let keyExists = modelEntitiesMaterials[entity.name] != nil
if keyExists {
entity.model!.materials = modelEntitiesMaterials[entity.name]!
}
if(entitiesState[entity.name] == .selected) {
//Color blue the selected item
entity.model?.materials[0] = selectedMaterial
}
}
}
@objc private func handleTap(sender: UITapGestureRecognizer) {
let tapLocation: CGPoint = sender.location(in: arView)
let result: [CollisionCastHit] = arView.hitTest(tapLocation)
guard let hitTest: CollisionCastHit = result.first, hitTest.entity.name != "Ground Plane"
else {
selectEntity(withSelectedEntity: nil)
return
}
let entity: ModelEntity = hitTest.entity as! ModelEntity
let keyExists = modelEntitiesMaterials[entity.name] != nil
if !keyExists {
modelEntitiesMaterials[entity.name] = entity.model!.materials
}
selectEntity(withSelectedEntity: entity)
}