Hello,
Does the Apple Vision Pro have an API for creating custom triggers for selecting things on the screen instead of the hand pinch gesture? For instance, using an external button/signal/controller instead of pinching fingers?
Hello,
Does the Apple Vision Pro have an API for creating custom triggers for selecting things on the screen instead of the hand pinch gesture? For instance, using an external button/signal/controller instead of pinching fingers?
Yes, visionOS supports Game Controller. Here's an example that uses GCController to enable a person to move a sphere along the x/y axis using a game controller. The example uses the the Entity Component System (ECS) paradigm. Understanding RealityKit’s modular architecture explains ECS in detail.
Create a RealityView
containing a sphere entity and listen for game controller updates. As they arrive update the entity's ControllerComponent
to reflect the game controller's state. More on ControllerComponent
in the next step.
struct ImmersiveView: View {
@State private var entity:ModelEntity?
var body: some View {
RealityView { content in
let entity = ModelEntity(mesh: .generateSphere(radius: 0.05), materials: [SimpleMaterial(color: .green, isMetallic: true)])
entity.position = [0, 1.2, -1.0]
content.add(entity)
self.entity = entity
}
.task {
NotificationCenter.default.addObserver(
forName: NSNotification.Name.GCControllerDidConnect,
object: nil, queue: nil) {
notification in
// Wait until you get a controller.
for controller in GCController.controllers() {
// Update the entity's component when a person interacts with the controller.
// This fires multiple times a second so store the controller state
// in a component then use a system to apply them every frame.
controller.extendedGamepad?.valueChangedHandler = { pad, _ in
Task { @MainActor in
guard let entity else {return}
entity.components.set(ControllerComponent(pad: pad))
}
}
}
}
}
}
}
Create a component to store the state of the controller.
struct ControllerComponent : Component {
let speed:Float = 1
let pad:GCExtendedGamepad
}
Create a system to adjust the entity's position based on the input received from the game controller.
struct ControllerSystem: System {
static let query = EntityQuery(where: .has(ControllerComponent.self))
public init(scene: RealityKit.Scene) {
}
// Extract the change in the controller's position every frame
// and use it to update the entity's position.
public func update(context: SceneUpdateContext) {
let entities = context.entities(matching: Self.query,
updatingSystemWhen: .rendering)
for entity in entities {
guard let component = entity.components[ControllerComponent.self] else {continue}
let leftThumbstick = component.pad.leftThumbstick
let xAxis:Float = leftThumbstick.xAxis.value
let yAxis:Float = leftThumbstick.yAxis.value
entity.position = entity.position + [xAxis, yAxis, 0] * component.speed * Float(context.deltaTime)
}
}
}
Register the component and system. You can do this in your app's initializer.
struct ControllerDemoApp: App {
init() {
ControllerComponent.registerComponent()
ControllerSystem.registerSystem()
}
}
Pair the game controller to your Vision Pro
See Connect headphones, game controllers, and other Bluetooth accessories to Apple Vision Pro to learn how to pair a game controller to your Vision Pro.
Note: The source for Happy Beam contains additional example code for enabling game controllers.