Adding gravity
Following on from adding a drag gesture, we can make it respond to gravity using a PhysicsBodyComponent.
Starting with a simple reflective cube this time, adjusting from the sphere in the drag example. I've also adjusted the scale and position to make it easier to see. In the video above, it's being shown in the "museum" environment as it has a good amount of floor space. This demo won't account for furniture.
RealityView { content in
// Cube entity
cube = ModelEntity(
mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(color: .white, isMetallic: true)])
// Scale and position
cube.scale = [3, 3, 3]
cube.position.y = 1
cube.position.z = -4
// Components
cube.components.set(GroundingShadowComponent(castsShadow: true))
cube.components.set(InputTargetComponent())
// Collisions
cube.generateCollisionShapes(recursive: true)
content.add(cube)
}
.gesture(
DragGesture()
.targetedToEntity(cube)
.onChanged { value in
cube.position = value.convert(value.location3D, from: .local, to: orb.parent!)
}
)
Adding physics #
The cube can be dragged around and will stay position when released. We can add some gravity physics to make it fall:
let physicsMaterial = PhysicsMaterialResource.generate(
staticFriction: 0.8,
dynamicFriction: 0.5,
restitution: 0.01 // How bouncy
)
cube.components[PhysicsBodyComponent.self] = .init(
massProperties: .default,
material: physicsMaterial,
mode: .dynamic
)
In this we're creating a PhysicsMaterialResource
which allows us to specify friction and restition
(bounciness). A low value here means it'll behave like a solid heavy block of metal. A higher value and it'll bounce around more.
We apply this PhysicsMaterialResource
as a material within the PhysicsBodyComponent
component, and set mode
to dynamic
so that it will move.
Creating a floor #
Without a floor, the cube just falls away. We can add a floor entity:
let floor = ModelEntity(
mesh: .generatePlane(width: 50, depth: 50),
materials: [OcclusionMaterial()]
)
floor.generateCollisionShapes(recursive: false)
floor.components[PhysicsBodyComponent.self] = .init(
massProperties: .default,
mode: .static
)
content.add(floor)
Here we generate a ModelEntity
made of a plane
and using an OcclusionMaterial. This is an invisible material which hides any objects rendered behind it.
With the physics enabled, the objects will fall and land on a "floor".
Finished code #
RealityView { content in
// Floor
let floor = ModelEntity(
mesh: .generatePlane(width: 50, depth: 50),
materials: [OcclusionMaterial()]
)
floor.generateCollisionShapes(recursive: false)
floor.components[PhysicsBodyComponent.self] = .init(
massProperties: .default,
mode: .static
)
content.add(floor)
// Cube
cube = ModelEntity(
mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(color: .white, isMetallic: true)])
// Scale and position
cube.scale = [3, 3, 3]
cube.position.y = 1
cube.position.z = -4
// Components
cube.components.set(GroundingShadowComponent(castsShadow: true))
cube.components.set(InputTargetComponent())
// Collisions
cube.generateCollisionShapes(recursive: true)
// Physics
let physicsMaterial = PhysicsMaterialResource.generate(
staticFriction: 0.8,
dynamicFriction: 0.5,
restitution: 0.01 // How bouncy
)
cube.components[PhysicsBodyComponent.self] = .init(
massProperties: .default,
material: physicsMaterial,
mode: .dynamic
)
content.add(cube)
}
.gesture(
DragGesture()
.targetedToEntity(cube)
.onChanged { value in
cube.position = value.convert(value.location3D, from: .local, to: orb.parent!)
}
)
- Previous: Dragging objects
- Next: Multiple objects