How to add attachments using RealityView in visionOS?

648 Views Asked by At

I have a RealityView and I want to add an Entity with an Attachment.

Assuming I have a viewModel manage my entities, and the addEntityGesture() will add a new Entity under the rootEntity.

I know that we can create attachment in the attachments closure, and add those attachments as entities in our make closure, however, what if I want to add entity with an attachment on the fly?

RealityView { content, attachments in
    // Load initial content
    content.add(viewModel.rootEntity)
} update: { updateContent, updateAttachments in
    //
} attachments: {
    //
}
.gesture(addEntityGesture())
1

There are 1 best solutions below

3
On BEST ANSWER

Adding attachments on the fly

To dynamically add an attachment in RealityView with a tap on a model, use the following code:

enter image description here

import SwiftUI
import RealityKit

struct ContentView : View {
    let man = try! Entity.load(named: "Man.usdz")
    @State var isTapped: Bool = false

    var body: some View {
        RealityView { content, attachments in
            man.position.z = -2
            man.playAnimation(man.availableAnimations[0].repeat())
            man.components[InputTargetComponent.self] = .init()
            man.generateCollisionShapes(recursive: true)
            content.add(man)                
        } update: { content, attachments in
            if isTapped {
                if let text = attachments.entity(for: "at01") {
                    text.position.z -= 1.7
                    text.position.y += 1.8
                    
                    content.entities.first?
                           .findEntity(named: "anyScene")?
                           .addChild(text, preservingWorldTransform: true)
                }
            }
        } attachments: {
            Attachment(id: "at01") {
                Text("Walking Man Animation").font(.extraLargeTitle)
            }
        }
        .gesture(
            SpatialTapGesture()
                .targetedToEntity(man)
                .onEnded { _ in
                    isTapped = true                        
                    Task {
                        try await Task.sleep(nanoseconds: 100_000)
                        isTapped = false
                    }
                }
        )
    }
}