Gesture filtering using .targetedToEntity(where: QueryPredicate<Entity>) is not working

I am trying to only apply a drag gesture to specific entities that has a specific component. My entities has the component on it along with the input target and collision component. The gestures work when I use .targetedToAnyEntity() modifier but .targetedToEntity(where:) modifier fails

struct ImmersiveView: View {
    var body: some View {
        RealityView { content in
            // Add the initial RealityKit content
            if let scene = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
                content.add(scene)
            }
        }
        .gesture(
            DragGesture()
                .targetedToEntity(where: .has(ToyComponent.self))
                .onChanged({ value in
                    value.entity.position = value.convert(value.location3D, from: .local, to: value.entity.parent!)
                })
        )
    }

}

What could be wrong here?

Answered by arthurfromberlin in 805905022

Hi @sarangb

Your approach to targeting a gesture to entities with a specific component looks correct to me, but since I can't see how/where you are creating the entities with the component it's a bit difficult for me to help you figure out what's going wrong. Could you show me how you are creating the entities with the ToyComponent?

Otherwise, here's an example that demonstrates how to use targetedToEntity(where:) to target a drag gesture to only the entities with a specific component.

struct ToyComponent: Component {
    
}

struct ImmersiveView: View {
    
    // Creates a sphere with a collision component and an input target component
    // that can be the target of drag gestures.
    func createDraggableSphere(color: SimpleMaterial.Color) -> Entity {
        let entity = ModelEntity(mesh: .generateSphere(radius: 0.05), materials: [SimpleMaterial(color: color, isMetallic: false)])
        entity.generateCollisionShapes(recursive: false)
        entity.components.set(InputTargetComponent())
        return entity
    }

    var body: some View {
        RealityView { content in
            // Create two draggable spheres that both have a `ToyComponent`.
            let toyEntity1 = createDraggableSphere(color: .green)
            toyEntity1.components.set(ToyComponent())
            toyEntity1.position = [-0.25, 1, -1]
            content.add(toyEntity1)
            
            let toyEntity2 = createDraggableSphere(color: .green)
            toyEntity2.components.set(ToyComponent())
            toyEntity2.position = [0, 1, -1]
            content.add(toyEntity2)
            
            // Create one draggable sphere without a `ToyComponent`.
            let nonToyEntity = createDraggableSphere(color: .red)
            nonToyEntity.position = [0.25, 1, -1]
            content.add(nonToyEntity)
        }
        .gesture(
            DragGesture()
                .targetedToEntity(where: .has(ToyComponent.self))
                .onChanged({ value in
                    value.entity.position = value.convert(value.location3D, from: .local, to: value.entity.parent!)
                })
        )
    }
}

This snippet creates three spheres with collision and input target components that can be the target of a drag gesture. Two of the spheres have ToyComponents (the green spheres) and one of the spheres does not (the red sphere). The drag gesture should only be able to target the two green spheres with the ToyComponents.

Let me know if you continue to run into any issues!

I created the ToyComponent in RealityComposerPro and attached to the root of the entities alongside with InputTarget and Collision Component.

So I realized something. If I assigned the ToyComponent, that I created as a new component in Reality composer pro in code using components.set(ToyComponent()) then that is working, but If I set the component in RealityComposerPro, that is not working for some reason. Seems like a bug

Accepted Answer

This was it. I didn't call register component. Calling it did the trick It was a bit confusing. So If I assign the component in code it works but if it is assigned in Reality Composer Pro it doesn't for that I have to call register component.

Is there a right place to call register component in the app? or just the closure of the reality view is fine?

Gesture filtering using .targetedToEntity(where: QueryPredicate&lt;Entity&gt;) is not working
 
 
Q