Targeting an Entity with Gesture Component

We can use three instance methods to access entities and additional features in our gestures.

Overview

In the last example we worked with Drag Gesture to transform an entity. We gained access to the entity inside by the gesture by passing in a weak reference. Let’s look at another way to access entities in our gestures.

We can use targetedToEntity(entity) on the gesture. SwiftUI will include all the original gesture data, along with some new features. We’ll have access to the entity on which the gesture was performed. We’ll also be able to use several convenient coordinate conversion methods.

Let’s convert the previous example to use this approach. We use .targetedToEntity(subject), passing in our subject entity. Inside the onChanged or onEnded closures, we can access the entity from the gesture value: value.entity

if let subject = scene.findEntity(named: "ToyRocket") {
    let drag = DragGesture(minimumDistance: 0.001)
        .targetedToEntity(subject)
        .onChanged { value in
            let subject = value.entity

            if !subject.components.has(InitialTransformComponent.self) {
                subject.components.set(InitialTransformComponent(transform: subject.transform))
            }

            guard let initialTransform = subject.components[InitialTransformComponent.self]?.transform else { return }

            let translation = value.translation3D
            var newTransform = initialTransform
            newTransform.translation.y += Float(translation.y)
            subject.transform = newTransform

        }
        .onEnded { value in
            value.entity.components.remove(InitialTransformComponent.self)
        }

    subject.components.set(GestureComponent(drag))
}

We can also use targetedToAnyEntity() and targetedToEntity(where:). For example, let’s make a gesture that we can use in multiple Gesture Components.

// Create a gesture to target any entity
var dragAny: some Gesture {
    DragGesture(minimumDistance: 0.001)
        .targetedToAnyEntity()
        .onChanged { value in
            let subject = value.entity

            if !subject.components.has(InitialTransformComponent.self) {
                subject.components.set(InitialTransformComponent(transform: subject.transform))
            }

            guard let initialTransform = subject.components[InitialTransformComponent.self]?.transform else { return }

            let translation = value.translation3D
            var newTransform = initialTransform
            newTransform.translation.y += Float(translation.y)
            subject.transform = newTransform

        }
        .onEnded { value in
            value.entity.components.remove(InitialTransformComponent.self)
        }
}

See also

Support our work so we can continue to bring you new examples and articles.

Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Questions or feedback?