You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从手势处理器中访问RealityViewContent实现点击创建虚拟对象?

解决RealityView手势中添加实体的问题

你遇到的核心问题是:手势闭包无法直接访问RealityView初始化闭包里的content参数,两者作用域相互隔离。下面是两种可行的实现方案:

方式一:用@State变量缓存待添加实体,在update闭包中处理

通过状态变量传递要添加的实体,利用RealityView的update闭包完成实体添加与事件订阅:

struct ContentView: View {
    // 用@State存储待添加的实体,可选类型标记是否有新实体需要处理
    @State private var entityToAdd: Entity?
    
    var body: some View {
        RealityView { content in
            // 初始化场景基础内容
        } update: { content in
            guard let newEntity = entityToAdd else { return }
            
            // 将实体添加到场景
            content.add(newEntity)
            // 订阅碰撞开始事件
            let collisionSubscription = content.subscribe(to: CollisionEvents.Began.self, on: newEntity) { event in
                print("碰撞触发:\(event.entityA) 与 \(event.entityB)")
            }
            // 需将collisionSubscription存入持久化变量(比如新增@State变量),避免被自动释放
            
            // 重置状态,防止重复添加
            entityToAdd = nil
        }
        .gesture(TapGesture().targetedToAnyEntity().onEnded { event in
            let square = create_a_square()
            // 设置实体位置为点击目标的位置
            square.position = event.entity.position
            // 赋值给状态变量,触发update闭包执行
            entityToAdd = square
        })
    }
    
    func create_a_square() -> Entity {
        // 实现正方形实体的创建逻辑
        let mesh = MeshResource.generateBox(size: 0.1)
        let material = SimpleMaterial(color: .red, isMetallic: false)
        let entity = ModelEntity(mesh: mesh, materials: [material])
        entity.generateCollisionShapes(recursive: true)
        return entity
    }
}

方式二:用@Observable对象管理实体列表

如果需要批量处理多个实体,使用可观察对象会更灵活:

// 定义可观察对象,统一管理待添加的实体
@Observable
class EntityManager {
    var entitiesToAdd: [Entity] = []
}

struct ContentView: View {
    private let entityManager = EntityManager()
    
    var body: some View {
        RealityView { content in
            // 初始化场景基础内容
        } update: { content in
            // 批量处理所有待添加的实体
            for entity in entityManager.entitiesToAdd {
                content.add(entity)
                let collisionSubscription = content.subscribe(to: CollisionEvents.Began.self, on: entity) { event in
                    print("碰撞触发:\(event.entityA.name) & \(event.entityB.name)")
                }
                // 将collisionSubscription存入entityManager,避免被释放
            }
            // 清空待添加列表
            entityManager.entitiesToAdd.removeAll()
        }
        .gesture(TapGesture().targetedToAnyEntity().onEnded { event in
            let square = create_a_square()
            square.position = event.entity.position
            entityManager.entitiesToAdd.append(square)
        })
    }
    
    func create_a_square() -> Entity {
        let mesh = MeshResource.generateBox(size: 0.1)
        let material = SimpleMaterial(color: .blue, isMetallic: true)
        let entity = ModelEntity(mesh: mesh, materials: [material])
        entity.generateCollisionShapes(recursive: true)
        return entity
    }
}

关键注意点

  • 不要直接在手势闭包里捕获content,RealityView的content会随视图更新重新创建,直接持有引用可能引发内存问题或异常。
  • 碰撞事件的订阅对象Subscription必须被持久化存储(比如存入@State或Observable对象),否则会被自动释放,无法接收后续事件。

内容的提问来源于stack exchange,提问作者DarkTrick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 06:42:42