苹果在 2019年推出了一个名为 Combine 的声明性异步事件处理框架,通过采用Combine 框架,可以集成事件处理代码并消除嵌套闭包和基于约定的回调,使代码更易于阅读和维护。Combine 框架 API都是使用类型安全的泛型实现,可以无缝接人已有工程,用于处理各类事件。在 Combine 框架中,最重要的3个组成部分是:Publisher (发布者)、Subscriber(订阅者)和 Operator (操作符)。Combine 事件处理机制是典型的观察者模式(与 RxSwift 中的 Observable、Observer 几平完全一致),Reality Kit 中的事件处理机制完全借用了 Combine,也包括 Publisher、Subscriber、Operator 3个组成部分,并且所有 Publisher 都遵循 Event 协议。目前,RealityKit 所有的事件如表 20所示。
表20 RealityKit 中的所有事件
所属事件类型 | 事件 | 描述 |
场景 |
SceneEvents.AnchoredStateChanged |
当场景中的 ARAnchor(包括所有遵循 HasAnchoring 协议的实体)状态发生改变时触发 |
SceneEvents.Update |
该事件每帧都会触发,因此可以执行自定义帧更新逻辑 |
|
动画 |
AnimationEvents. PlaybackCompleted |
当动画播放完毕时触发 |
AnimationEvents. PlaybackLooped |
当动画循环播放时触发 |
|
AnimationEvents. Playback Terminated |
当动画被中止时触发,包括播放完毕或者被中断 |
|
音频 |
AudioEvents. PlaybackCompleted |
当音频播放完毕时触发 |
碰撞 |
CollisionEvents. Began |
当两个带碰撞器的对象碰撞开始时触发,每次碰撞只触发一次 |
CollisionEvents. Updated |
当两个带碰撞器的对象碰撞接触后每帧都会触发 |
|
CollisionEvents. Ended |
当两个带碰撞器的对象发生碰撞后脱离接触时触发,每次碰撞只触发一次 |
|
网络同步 |
SynchronizationEvents. OwnershipChanged |
当一个实体对象的所有权属性发生改变时触发 |
SynchronizationEvents. OwnershipRequest |
当一个网络参与者申请对某个实体对象的所有权时触发 |
RealityKit 中的所有事件都可以通过 subscribe(to:on:_:)方法订阅监听,并且所有的事件处理遵循相司的步骤与流程,因此只要理解并掌握一种事件处理方法就可以推广到所有其他类型事件的处理中。
下面以碰撞事件(Collision Events)为例讲解 RealityKit 事件的一般处理方法。通常,在需要处理某类耳件之前需先订阅(subscribe)该事件,在RealityKit 中,我们使用 scene完成订阅操作,典型代码如下
import SwiftUI import RealityKit import ARKit import Combine struct RealityKitEventView : View { var body: some View { return ARViewContainer8().edgesIgnoringSafeArea(.all) } } struct ARViewContainer8: UIViewRepresentable { func makeUIView(context: Context) -> ARView { let arView = ARView(frame: .zero) let config = ARWorldTrackingConfiguration() config.planeDetection = .horizontal arView.session.run(config, options: []) arView.setupGestures() return arView } func updateUIView(_ uiView: ARView, context: Context) {} } extension ARView{ func setupGestures() { let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:))) self.addGestureRecognizer(tap) } @objc func handleTap(_ sender: UITapGestureRecognizer? = nil) { guard let touchInView = sender?.location(in: self) else { return } guard let raycastQuery = self.makeRaycastQuery(from: touchInView, allowing: .existingPlaneInfinite,alignment: .horizontal) else { return } guard let result = self.session.raycast(raycastQuery).first else {return} let transformation = Transform(matrix: result.worldTransform) let box = CustomEntity(color: .yellow,position: transformation.translation) self.installGestures(.all, for: box) box.addCollisions(scene: self) self.scene.addAnchor(box) } } //自定义实体类 class CustomEntity: Entity, HasModel, HasAnchoring, HasCollision { var subscribes: [Cancellable] = [] required init(color: UIColor) { super.init() //设置碰撞组件,可以和其他实体发生碰撞 self.components.set(CollisionComponent( shapes: [.generateBox(size: [0.1,0.1,0.1])], mode: .default, filter: CollisionFilter(group: CollisionGroup(rawValue: 1), mask: CollisionGroup(rawValue: 1)) )) //添加组件,定义实体的模型资源 self.components.set( ModelComponent( mesh: .generateBox(size: [0.1,0.1,0.1]), materials: [SimpleMaterial(color: color,isMetallic: false)] )) } convenience init(color: UIColor, position: SIMD3<Float>) { self.init(color: color) self.position = position } required init() { fatalError("init()没有执行,初始化不成功") } func addCollisions(scene: ARView) { subscribes.append(scene.scene.subscribe(to: CollisionEvents.Began.self, on: self) { event in guard let box = event.entityA as? CustomEntity else { return } //发生碰撞时把实体变成红色 box.model?.materials = [SimpleMaterial(color: .red, isMetallic: false)] }) subscribes.append(scene.scene.subscribe(to: CollisionEvents.Ended.self, on: self) { event in guard let box = event.entityA as? CustomEntity else { return } box.model?.materials = [SimpleMaterial(color: .yellow, isMetallic: false)] }) } }
标签:box,触发,color,self,碰撞,Reality,let,事件,Kit From: https://www.cnblogs.com/duzhaoquan/p/17969730