I have a .rcproject
file with a goal (football gate) and a ball, the ball has physics of Dynamic and Rubber material, and the goal is Fixed with Lead material. When I load the scene from the .rcproject
file, I set the goal collider to be the exact mesh of the tubes that make the goal's frame and the net, using generateConvex
of the model.mesh
.
But, it seems like the ball is touching the goal, and it collides with some invisible wall that is at the "entrance" of the goal, kinda like it's just a 2d wall, instead of the ball actually going inside the goal like it would in real life. This is my code:
Experience.loadSceneAsync { result in
switch result {
case let .success(scene):
guard let tubeOneGeometry = scene.findEntity(named: "Tube_Red_0")?.children[0] as? ModelEntity,
let tubeTwoGeometry = scene.findEntity(named: "Tube_White_0")?.children[0] as? ModelEntity,
let netGeometry = scene.findEntity(named: "Net_Net_0")?.children[0] as? ModelEntity,
let tubeOneMesh = tubeOneGeometry.model?.mesh,
let tubeTwoMesh = tubeTwoGeometry.model?.mesh,
let netMesh = netGeometry.model?.mesh,
let goal = scene.goal
else { return }
let tubeOneShape = ShapeResource.generateConvex(from: tubeOneMesh)
let tubeTwoShape = ShapeResource.generateConvex(from: tubeTwoMesh)
let netShape = ShapeResource.generateConvex(from: netMesh)
goal.components[CollisionComponent.self] = CollisionComponent(
shapes: [tubeOneShape, tubeTwoShape, netShape])
arView.debugOptions.insert(.showPhysics)
let anchor = AnchorEntity(plane: .horizontal)
anchor.addChild(scene)
arView.scene.addAnchor(anchor)
case let .failure(error):
print("Failed to load scene: \(error)")
}
}
You forgot to turn the default collision shape for the football gate OFF. Also, the generateConvex(from:) method built an irregularly shaped collision shape. Use the following code to generate robust collision shape programmatically (however, a good practice is to create a low-resolution collision shape in 3D authoring apps like Autodesk Maya):
import UIKit
import RealityKit
class ViewController: UIViewController {
@IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
Experience.loadSoccerAsync { result in
switch result {
case let .success(scene):
guard let goal = scene.goal else { return }
goal.components[CollisionComponent.self] = .none
let right = ShapeResource.generateCapsule(height: 3, radius: 0.13)
.offsetBy(translation: [0,1.5,1.83])
let left = ShapeResource.generateCapsule(height: 3, radius: 0.13)
.offsetBy(translation: [0,1.5,-1.83])
let upper = ShapeResource.generateCapsule(height: 4.1, radius: 0.12)
.offsetBy(rotation: simd_quatf(angle: .pi/2, axis: [1,0,0]),
translation: [0,2.8,0])
let net = ShapeResource.generateBox(width: 0.01, height: 3.3, depth: 3.9)
.offsetBy(rotation: simd_quatf(angle: -.pi/4, axis: [0,0,1]),
translation: [-1.3,1.4,0])
goal.components[CollisionComponent.self] =
CollisionComponent(shapes: [right, left, upper, net])
self.arView.debugOptions = [.showPhysics]
goal.scale /= 2
let anchor = AnchorEntity()
anchor.addChild(scene)
self.arView.scene.addAnchor(anchor)
case let .failure(error):
print("Failed to load scene: \(error)")
}
}
}
}