I’m attempting to detect collisions between two RealityKit entities, however the outcomes are surprising.
I thus created a minimal instance. Within the iOS app beneath, 3 entities are arrange:
A board
, a hard and fast field
and a transferring field
.
The board and the first field do not transfer, whereas the 2nd field strikes in direction of the first field.
All 3 entities have a collisionShape
.
As a result of Physics simulation will not be used, each bins have their collision mode set to .set off
.
Each bins belong to the identical CollisionGroup
, and their collision filter is ready to this group.
A CollisionManager
subscribes to the start of collision occasions. If a collision is detected, the collision is logged.
When the app is began, the 2nd field is transferring in direction of the first one till each are on the similar place. No collision is logged. I anticipated that the collision between each bins can be detected.
If setting of the collision filter of a field is out commented, the next is logged when the app begins (the numerous RealityKit logs are omitted):
collision started between board and Fastened field
collision started between Fastened field and board
collision started between board and Shifting field
collision started between Shifting field and board
Clearly, collision may be detected, however a collision between each bins will not be. However why?
Right here is my code:
//
// CollisionApp.swift
// Collision
//
// Created by Reinhard Männer on 31.03.25.
//
import SwiftUI
@predominant
struct CollisionApp: App {
var physique: some Scene {
WindowGroup {
ContentView()
}
}
}
//
// CollisionManager.swift
// Collision
//
// Created by Reinhard Männer on 31.03.25.
//
import Mix
import Basis
import RealityKit
class CollisionManager {
var movementTimer: Timer?
personal var updateVehicleCollisionSubscription: Cancellable?
func startVehicleCollisionTrigger(scene: RealityKit.Scene) {
updateVehicleCollisionSubscription = scene.subscribe(to: CollisionEvents.Started.self) { occasion in
let a = occasion.entityA
let b = occasion.entityB
print("collision started between (a.title) and (b.title)")
}
}
func startMovement(entity: Entity) {
movementTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
if entity.place.x > 0 {
entity.place.x -= 0.02
} else {
timer.invalidate()
self.movementTimer = nil
}
}
}
}
//
// ContentView.swift
// Collision
//
// Created by Reinhard Männer on 31.03.25.
//
import RealityKit
import SwiftUI
struct ContentView: View {
let collisionManager = CollisionManager()
let boardHeight: Float = 0.1
let boxHeight: Float = 0.3
var physique: some View {
var movingBox: Entity?
RealityView { content material in
let board = makeBoard()
content material.add(board)
let box1 = makeBox(title: "Fastened field")
board.addChild(box1)
movingBox = makeBox(title: "Shifting field")
movingBox?.place.x = 0.8
board.addChild(movingBox!)
}
replace: { content material in
let scene = content material.entities.first?.scene
collisionManager.startVehicleCollisionTrigger(scene: scene!)
collisionManager.startMovement(entity: movingBox!)
}
}
func makeBoard() -> ModelEntity {
let mesh = MeshResource.generateBox(width: 2.0, peak: boardHeight, depth: 1.0)
var materials = UnlitMaterial(); materials.coloration.tint = .pink
let boardEntity = ModelEntity(mesh: mesh, supplies: [material])
boardEntity.title = "board"
boardEntity.generateCollisionShapes(recursive: false)
boardEntity.remodel.translation = [0, 0, -3]
return boardEntity
}
func makeBox(title: String) -> ModelEntity {
let mesh = MeshResource.generateBox(width: 0.2, peak: boxHeight, depth: 0.3)
var materials = UnlitMaterial(); materials.coloration.tint = .inexperienced
let boxEntity = ModelEntity(mesh: mesh, supplies: [material])
boxEntity.title = title
// To place the field onto the board, transfer it up by half peak of the board and half peak of the field
let y_up = boardHeight/2.0 + boxHeight/2.0
boxEntity.place = SIMD3(0, y_up, 0)
// Permit to detect collisions between bins solely and to set off code execution.
boxEntity.generateCollisionShapes(recursive: false)
boxEntity.collision!.mode = .set off
let collisionGroup = CollisionGroup(rawValue: 1 << 0)
let filter = CollisionFilter(group: collisionGroup, masks: collisionGroup)
boxEntity.collision!.filter = filter
return boxEntity
}
}