Collisions & Physics: Hello Physics Motion Component

We can use this component to read or write angular and linear velocity.

Overview

When we took a look at Physics Body, I left this note at the end of the post.

Two values that are noticeably missing are included in another component. We can add a Physics Motion component if we need to access or change linear or angular velocity.

Let’s take a look at this simple component. It has two instance properties

  1. angularVelocity – A vector that defines how fast and in what direction an entity rotates (or spins).
  2. linearVelocity – A vector that defines how fast and in what direction an entity translates (or moves).

Adding angularVelocity: We get the component from the entity, calculate a new random vector, and re-add the component.

if var motion = subjectEntity.components[PhysicsMotionComponent.self] {
  let angularVelocity: SIMD3<Float> = SIMD3.random(in: 1...5)
  motion.angularVelocity += angularVelocity
  subjectEntity.components.set(motion)
}

We can do the same thing for linearVelocity.

if var motion = subjectEntity.components[PhysicsMotionComponent.self] {
  let linearVelocity: SIMD3<Float> = SIMD3.random(in: 0.5...2.5)
  motion.linearVelocity += linearVelocity
  subjectEntity.components.set(motion)
}

A common use case of this component is to remove any movement and rotation on an entity. For example, an object pooling system may want to remove or reset all velocity when placing an entity back in the pool. You can see an example of that in Lab 043

Removing all velocity:

// Zero out current values
if var motion = subjectEntity.components[PhysicsMotionComponent.self] {
  let angularVelocity: SIMD3<Float> = SIMD3.random(in: 1...5)
  motion.angularVelocity = .zero
  motion.linearVelocity = .zero
  subjectEntity.components.set(motion)
}

// Or just assign an new instance, which will have zero for both values 
subjectEntity.components.set(PhysicsMotionComponent())

Note that this component is essentially ignored when used on static physics bodies. We can use it to move or spin kinematic bodies. It can also be used on dynamic bodies, but will be quickly overwritten with new data from the physics simulation. The subject in this demo has a dynamic body. We can apply velocity at the press of a button, but it acts more like applying an impulse then a fixed value.

Video Demo

Example Code

struct Example063: View {

    @State var subjectEntity = Entity()

    var body: some View {
        RealityView { content in

            guard let scene = try? await Entity(named: "PhysicsMotionBasics", in: realityKitContentBundle) else { return }

            content.add(scene)

            if let subject = scene.findEntity(named: "Subject") {
                subjectEntity = subject
            }
        }
        .ornament(attachmentAnchor: .scene(.trailingFront), ornament: {
            VStack {

                Button(action:  {
                    if var motion = subjectEntity.components[PhysicsMotionComponent.self] {
                        let angularVelocity: SIMD3<Float> = SIMD3.random(in: 1...5)
                        motion.angularVelocity += angularVelocity
                        subjectEntity.components.set(motion)
                    }
                }, label: {
                    Label("Add angular velocity", systemImage: "rotate.3d")
                        .frame(maxWidth: .infinity, alignment: .leading)
                })

                Button(action:  {
                    if var motion = subjectEntity.components[PhysicsMotionComponent.self] {
                        let linearVelocity: SIMD3<Float> = SIMD3.random(in: 0.5...2.5)
                        motion.linearVelocity += linearVelocity
                        subjectEntity.components.set(motion)
                    }
                }, label: {
                    Label("Add linear velocity", systemImage: "move.3d")
                        .frame(maxWidth: .infinity, alignment: .leading)
                })

                Button(action:  {
                    // Reset the transform
                    var transformReset = Transform()
                    transformReset.translation = [0, 0.1, 0]
                    subjectEntity.transform = transformReset

                    // Remove any velocity by assigning a new instance of the component
                    subjectEntity.components.set(PhysicsMotionComponent())
                }, label: {
                    Label("Reset all velocity", systemImage: "arrow.trianglehead.counterclockwise")
                        .frame(maxWidth: .infinity, alignment: .leading)
                })
            }
            .padding()
            .glassBackgroundEffect()
        })
    }
}

Support our work so we can continue to bring you new examples and articles.

Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Questions or feedback?