Dragging objects
With the 3D orb created in this post, we can enable dragging with gestures.
Starting code #
We begin with some code that sets up a RealityView
and creates a shiny metallic orb. It sets the scale and position so that it's in front of us.
struct ImmersiveView: View {
var body: some View {
RealityView { content in
orb = ModelEntity(
mesh: .generateSphere(radius: 0.1),
materials: [SimpleMaterial(color: .white, isMetallic: true)])
// Scale and position
orb.scale = [2, 2, 2]
orb.position.y = 0.75
orb.position.z = -1
content.add(orb)
}
}
}
Adding gesture #
Interaction in visionOS is handled using gestures.
We add a gesture to our RealityView
like so, and pass in a DragGesture
.
RealityView { content in
//... orb code
}
.gesture(
DragGesture()
.targetedToEntity(orb)
.onChanged { value in
orb.position = value.convert(value.location3D, from: .local, to: orb.parent!)
}
)
The DragGesture
is configured using targetedToEntity
, which specifies which entity to use, and then we listen for an onChange
event. This event gives us the value, as a location3D
entry. We need to convert that to work with the Set3D
coordinates used by our orb.
With the gesture in place, it's not working quite yet. We can make the position change stick by applying some modifiers to the orb.
Components and collisions #
Inside the RealityView
struct, add some configuration to tell the orb to receive the position change:
// Components
orb.components.set(InputTargetComponent())
// Collisions
orb.generateCollisionShapes(recursive: true)
The first component is InputTargetComponent. We set this to configure which sorts of allowedInputTypes
it can receive. By default it is all
, though if we want that can be configured by passing in an allowedInputTypes
value.
We then set generateCollisionShapes
with recursive
set to true.
With these in place, we can drag the orb around.
Adding shadow #
For some polish, and to help see where the orb is when moving it, we can add a shadow:
orb.components.set(GroundingShadowComponent(castsShadow: true))
Finished code #
Putting it all together, the finished draggable result is:
struct ImmersiveView: View {
@State private var orb = ModelEntity()
var body: some View {
RealityView { content in
orb = ModelEntity(
mesh: .generateSphere(radius: 0.1),
materials: [SimpleMaterial(color: .white, isMetallic: true)])
// Scale and position
orb.scale = [2, 2, 2]
orb.position.y = 0.75
orb.position.z = -1
// Components
orb.components.set(InputTargetComponent(allowedInputTypes: .indirect))
orb.components.set(GroundingShadowComponent(castsShadow: true))
// Collisions
orb.generateCollisionShapes(recursive: true)
content.add(orb)
}
.gesture(
DragGesture()
.targetedToEntity(orb)
.onChanged { value in
orb.position = value.convert(value.location3D, from: .local, to: orb.parent!)
}
)
}
}
- Previous: Immersive spaces
- Next: Adding gravity