Lab 047 – Emoji Friends
Making some little emoji spheres to bounce around my office.
I just wanted to make something fun today. I loop over an array of emoji and create attachments for each one. Then I loop over them in the make closure to create an entity for each one, including the attachment as a child. I used some basic ARKit Plane Detection to add planes with collisions and physics. When I tap each sphere some random motion is applied.
Video demo showing emoji spheres bouncing around my office
Full Lab Code
struct Lab047: View {
@State var session = ARKitSession()
@State var planeAnchorsSimple: [UUID: Entity] = [:]
var body: some View {
let emoji = ["😀", "😃", "😄", "😁", "😆", "☺️", "😊", "🙃", "😌", "😛", "😝", "😜", "🤪", "🤓", "😎", "🙂↔️"]
RealityView { content, attachments in
for em in emoji {
if let em = attachments.entity(for: em) {
let parent = Entity()
// Just a hack to have an inside-out sphere
let model = ModelEntity(
mesh: .generateSphere(radius: 0.1),
materials: [SimpleMaterial(color: .black, isMetallic: false)])
model.scale = SIMD3(x: -1, y: 1, z: 1) // flip this inside out
parent.addChild(model)
// Calculate a random position
let x: Float = Float.random(in: -1...1)
let y: Float = Float.random(in: 0...2)
let z: Float = Float.random(in: -1...1)
parent.position = SIMD3<Float>(x, y, z)
let collision = CollisionComponent(shapes: [.generateSphere(radius: 0.1)])
var physics = PhysicsBodyComponent(
shapes: [.generateSphere(radius: 0.1)],
mass: 1.0,
material: .generate(friction: 0, restitution: 1),
mode: .dynamic
)
physics.isAffectedByGravity = false
let input = InputTargetComponent()
parent.components.set([collision, physics, input])
em.components.set([BillboardComponent(), HoverEffectComponent()])
parent.addChild(em)
content.add(parent)
}
}
} update: { content, attachments in
for (_, entity) in planeAnchorsSimple {
if !content.entities.contains(entity) {
content.add(entity)
}
}
} attachments: {
ForEach(emoji, id: \.self) { em in
Attachment(id: em) {
Text(em)
.font(.system(size: 144))
}
}
}
.gesture(TapGesture()
.targetedToAnyEntity()
.onEnded { value in
applyMotion(entity: value.entity)
})
.task {
try! await setupAndRunPlaneDetection()
}
}
func setupAndRunPlaneDetection() async throws {
let planeData = PlaneDetectionProvider(alignments: [.horizontal, .vertical, ])
if PlaneDetectionProvider.isSupported {
do {
try await session.run([planeData])
for await update in planeData.anchorUpdates {
switch update.event {
case .added, .updated:
let anchor = update.anchor
let planeEntitySimple = createSimplePlaneEntity(for: anchor)
planeAnchorsSimple[anchor.id] = planeEntitySimple
case .removed:
let anchor = update.anchor
planeAnchorsSimple.removeValue(forKey: anchor.id)
}
}
} catch {
print("ARKit session error \(error)")
}
}
}
func createSimplePlaneEntity(for anchor: PlaneAnchor) -> Entity {
let extent = anchor.geometry.extent
let mesh = MeshResource.generatePlane(width: extent.width, height: extent.height)
let material = OcclusionMaterial()
let entity = ModelEntity(mesh: mesh, materials: [material])
entity.transform = Transform(matrix: matrix_multiply(anchor.originFromAnchorTransform, extent.anchorFromExtentTransform))
entity.generateCollisionShapes(recursive: true, static: true)
let physicsMaterial = PhysicsMaterialResource.generate(friction: 0, restitution: 1)
let physics = PhysicsBodyComponent(massProperties: .default, material: physicsMaterial, mode: .static)
entity.components.set(physics)
return entity
}
func applyMotion(entity: Entity) {
// Add some force when we tap on any of the flowers
let force = SIMD3<Float>(
x: Float.random(in: -1...1),
y: Float.random(in: -1...1),
z: Float.random(in: -1...1)
)
var motion = PhysicsMotionComponent()
motion.linearVelocity = force * 4
entity.components.set(motion)
}
}Support our work so we can continue to bring you new examples and articles.

Follow Step Into Vision