Responding to gestures on an entity
Respond to gestures performed on RealityKit entities using input target and collision components.
Overview
Your app responds to RealityView gesture events received from SwiftUI by adding an InputTargetComponent and a CollisionComponent to your entities. Add a HoverEffectComponent to the entity so it highlights as the gaze intersects the collision shape. The input target component marks the entity as participating in the event system. The system uses the collision component to test if the gaze vector intersects the entity. With both components attached, entities receive events. With the hover effect attached the entity visually appears ready to receive events.
Attach components to an entity to process events
The sample defines the ActiveComponent, which keeps track of the active state of the entity.
public class ActiveComponent: Component {
public var active: Bool = false
}This sample has one entity, a cube that’s 0.1 units in each direction. The sample creates the entity then adds the components.
var cube = ModelEntity(mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(color: .orange, isMetallic: false)])
cube.components.set(InputTargetComponent())
cube.components.set(CollisionComponent(shapes: [ShapeResource.generateBox(size: SIMD3<Float>(0.1, 0.1, 0.1))]))
cube.components.set(HoverEffectComponent())
cube.components.set(ActiveComponent())The sample has a SpatialEventGesture attached to the RealityView. As the person interacting with the app looks around and pinches, the system uses the input target component and the collision component to determine intent. The system considers all entities in the scene because the sample calls targetedToAnyEntity(). When the person pinches on the cube the system invokes the gesture’s onEnded block, which toggles the active flag.
.gesture(SpatialEventGesture()
.targetedToAnyEntity()
.onEnded { value in
value.entity.components[ActiveComponent.self]?.active.toggle()
})The attachments: block creates an attachment with the name of the cube entity.
attachments: {
Attachment(id: cube.id) {
Text("\(cube.name)")
.padding()
.glassBackgroundEffect(in: RoundedRectangle(cornerRadius: 5.0))
.tag(cube.id)
}
}The attachment’s id is set to the ID of the cube so that it’s easy to find in the update: block of RealityView. In the update: block, the sample finds the ActiveComponent from the cube and then finds the attachment using the ID of the cube. If the active value is true the code adds a BillboardComponent to the attachment. The system ensures entities with a BillboardComponent always face the person. The RealityView update block adds the attachment entity as a subentity of the cube and sets the position to [0.0, 0.1, 0.0].
update: { content, attachments in
guard let component = cube.components[ActiveComponent.self] else { return }
guard let attachmentEntity = attachments.entity(for: cube.id) else { return }
if component.active {
attachmentEntity.components.set(BillboardComponent())
cube.addChild(attachmentEntity)
attachmentEntity.setPosition(SIMD3<Float>(0.0, 0.1, 0.0),
relativeTo: cube)
} else {
cube.removeChild(attachmentEntity)
}
}See Also
Scene content
Hello WorldEnabling video reflections in an immersive environmentCreating a spatial drawing app with RealityKitGenerating interactive geometry with RealityKitCombining 2D and 3D views in an immersive appTransforming RealityKit entities using gesturesModels and meshesMaterials, textures, and shadersAnchorsLights and camerasContent synchronizationAudioVideosImages