RealityKit中球体穿过平面未触发碰撞,如何解决?
问题修复方案
核心问题分析
- 平面缺少物理体配置:仅设置碰撞形状不足以让物理引擎识别平面为碰撞实体,必须添加
HasPhysicsBody协议并配置静态物理体。 - 碰撞订阅被提前销毁:
subscriptions是makeUIView内的局部变量,方法执行完毕后会被释放,导致碰撞事件监听失效。 - 强制类型转换存在风险:直接声明实体需遵循的协议,比强制类型转换更安全清晰。
修复后的完整代码
import SwiftUI import RealityKit import Combine struct ARViewContainer: UIViewRepresentable { // 将订阅存储提升为结构体属性,避免提前释放 private var subscriptions = Set<AnyCancellable>() func makeUIView(context: Context) -> ARView { let arView = ARView(frame: .zero) let anchor = AnchorEntity() // 创建带物理体的平面 let planeModel = ModelEntity( mesh: .generatePlane(width: 2.0, depth: 2.0), materials: [SimpleMaterial(color: .gray, isMetallic: false)] ) as Entity & HasCollision & HasPhysicsBody planeModel.position = [0, -10, -1.5] planeModel.generateCollisionShapes(recursive: true) planeModel.physicsBody = .init() planeModel.physicsBody?.mode = .static // 设置为静态物理体,固定不动 // 创建球体 let ballModel = ModelEntity( mesh: .generateSphere(radius: 0.4), materials: [SimpleMaterial(color: .red, isMetallic: true)] ) as Entity & HasCollision & HasPhysicsBody ballModel.generateCollisionShapes(recursive: true) ballModel.position = [0, 0, -1.5] ballModel.physicsBody = .init() ballModel.physicsBody?.mode = .dynamic // 持久化碰撞事件订阅 arView.scene.subscribe(to: CollisionEvents.Began.self, on: ballModel) { _ in print("OCCURED!") }.store(in: &subscriptions) anchor.addChild(ballModel) anchor.addChild(planeModel) arView.scene.addAnchor(anchor) return arView } func updateUIView(_ uiView: ARView, context: Context) {} }
关键修复说明
- 给平面添加
HasPhysicsBody协议并设置static模式,让物理引擎将其识别为可碰撞的地面。 - 将
subscriptions改为结构体属性(使用Set<AnyCancellable>规范存储),确保订阅在ARView生命周期内持续生效。 - 优化实体类型声明方式,替代强制类型转换,提升代码安全性和可读性。
内容的提问来源于stack exchange,提问作者saro
相关产品推荐
相关产品推荐

