Collision detection

How to detect whether two entities collide in RealityView and execute some instructions after the collision. It is assumed that both entities have collision components, and one of them also has an anchor component (such as a binding hand).

Answered by Vision Pro Engineer in 807037022

Hi @lijiaxu

You can detect collisions by subscribing to collision events on an entity. For example, if you have an entity with a collision component, myEntity, you can subscribe to its various collision events like so:

@State private var collisionBegan: EventSubscription?
@State private var collisionUpdated: EventSubscription?
@State private var collisionEnded: EventSubscription?

var body: some View {
    RealityView { content in
        // Create myEntity here.
        ...
        
        // Subscribe to collision events.
        collisionBegan = content.subscribe(to: CollisionEvents.Began.self, on: myEntity) { collisionEvent in
            print("Collision began.")
        }

        collisionUpdated = content.subscribe(to: CollisionEvents.Updated.self, on: myEntity) { collisionEvent in
            print("Collision updated.")
        }

        collisionEnded = content.subscribe(to: CollisionEvents.Ended.self, on: myEntity) { collisionEvent in
            print("Collision ended.")
        }
    }
}

In this case, I call a print statement when the collision occurs, but you can execute whatever instructions you like in the collision event callback.

Things get a little bit more complicated when an entity with an AnchoringComponent is involved, as you will need to set its physicsSimulation property to .none, as well as start a SpatialTrackingSession. Here's a snippet that demonstrates how to do that:

@State private var collisionBegan: EventSubscription?
@State private var collisionUpdated: EventSubscription?
@State private var collisionEnded: EventSubscription?

var body: some View {
    RealityView { content in
        // Start a spatial tracking session for the hands.
        let configuration = SpatialTrackingSession.Configuration(tracking: [.hand])
        let session = SpatialTrackingSession()
        await session.run(configuration)
        
        // Create a cube with collision.
        let collidableCube = ModelEntity(mesh: .generateBox(size: 0.2), materials: [SimpleMaterial(color: .green.withAlphaComponent(0.75), isMetallic: false)])
        collidableCube.position = [0, 1, -0.5]
        collidableCube.generateCollisionShapes(recursive: false)
        content.add(collidableCube)
        
        // Create an anchor entity with collision tracking the right index finger tip.
        let rightIndexTipAnchor = AnchorEntity(.hand(.right, location: .indexFingerTip))
        rightIndexTipAnchor.anchoring.physicsSimulation = .none
        rightIndexTipAnchor.components.set(ModelComponent(mesh: .generateSphere(radius: 0.01), materials: [SimpleMaterial()]))
        rightIndexTipAnchor.components.set(CollisionComponent(shapes: [.generateSphere(radius: 0.01)]))
        content.add(rightIndexTipAnchor)
        
        // Subscribe to collision events.
        collisionBegan = content.subscribe(to: CollisionEvents.Began.self, on: rightIndexTipAnchor) { collisionEvent in
            print("Collision began.")
        }
        collisionUpdated = content.subscribe(to: CollisionEvents.Updated.self, on: rightIndexTipAnchor) { collisionEvent in
            print("Collision updated.")
        }
        collisionEnded = content.subscribe(to: CollisionEvents.Ended.self, on: rightIndexTipAnchor) { collisionEvent in
            print("Collision ended.")
        }
    }
}

For this approach, be sure to add an entry for NSHandsTrackingUsageDescription to your app’s information property list to provide a usage description that explains how your app uses the hand tracking information.

Accepted Answer

Hi @lijiaxu

You can detect collisions by subscribing to collision events on an entity. For example, if you have an entity with a collision component, myEntity, you can subscribe to its various collision events like so:

@State private var collisionBegan: EventSubscription?
@State private var collisionUpdated: EventSubscription?
@State private var collisionEnded: EventSubscription?

var body: some View {
    RealityView { content in
        // Create myEntity here.
        ...
        
        // Subscribe to collision events.
        collisionBegan = content.subscribe(to: CollisionEvents.Began.self, on: myEntity) { collisionEvent in
            print("Collision began.")
        }

        collisionUpdated = content.subscribe(to: CollisionEvents.Updated.self, on: myEntity) { collisionEvent in
            print("Collision updated.")
        }

        collisionEnded = content.subscribe(to: CollisionEvents.Ended.self, on: myEntity) { collisionEvent in
            print("Collision ended.")
        }
    }
}

In this case, I call a print statement when the collision occurs, but you can execute whatever instructions you like in the collision event callback.

Things get a little bit more complicated when an entity with an AnchoringComponent is involved, as you will need to set its physicsSimulation property to .none, as well as start a SpatialTrackingSession. Here's a snippet that demonstrates how to do that:

@State private var collisionBegan: EventSubscription?
@State private var collisionUpdated: EventSubscription?
@State private var collisionEnded: EventSubscription?

var body: some View {
    RealityView { content in
        // Start a spatial tracking session for the hands.
        let configuration = SpatialTrackingSession.Configuration(tracking: [.hand])
        let session = SpatialTrackingSession()
        await session.run(configuration)
        
        // Create a cube with collision.
        let collidableCube = ModelEntity(mesh: .generateBox(size: 0.2), materials: [SimpleMaterial(color: .green.withAlphaComponent(0.75), isMetallic: false)])
        collidableCube.position = [0, 1, -0.5]
        collidableCube.generateCollisionShapes(recursive: false)
        content.add(collidableCube)
        
        // Create an anchor entity with collision tracking the right index finger tip.
        let rightIndexTipAnchor = AnchorEntity(.hand(.right, location: .indexFingerTip))
        rightIndexTipAnchor.anchoring.physicsSimulation = .none
        rightIndexTipAnchor.components.set(ModelComponent(mesh: .generateSphere(radius: 0.01), materials: [SimpleMaterial()]))
        rightIndexTipAnchor.components.set(CollisionComponent(shapes: [.generateSphere(radius: 0.01)]))
        content.add(rightIndexTipAnchor)
        
        // Subscribe to collision events.
        collisionBegan = content.subscribe(to: CollisionEvents.Began.self, on: rightIndexTipAnchor) { collisionEvent in
            print("Collision began.")
        }
        collisionUpdated = content.subscribe(to: CollisionEvents.Updated.self, on: rightIndexTipAnchor) { collisionEvent in
            print("Collision updated.")
        }
        collisionEnded = content.subscribe(to: CollisionEvents.Ended.self, on: rightIndexTipAnchor) { collisionEvent in
            print("Collision ended.")
        }
    }
}

For this approach, be sure to add an entry for NSHandsTrackingUsageDescription to your app’s information property list to provide a usage description that explains how your app uses the hand tracking information.

Collision detection
 
 
Q