Search code examples
swiftgame-physicsarkitrealitykit

RealityKit – Add force to Entity at specific point


I have my entity which has also physics I check for it with the if let syntax:

if let scoot = scooter as? HasPhysics { ... }

this works as charm I am able to get the user tap by using UITapGestureRecognizer this is just the first iteration I would like to use the swipe or pan gestures ideally.

// I can get the location of the tap in the arView
let location =  sender.location(in: arView)

// I can use this three approaches both of them returns me the Entity not sure which to use though
let hittest = arView.hitTest(location)
let results = arView.raycast(from: location, allowing: .existingPlaneInfinite, alignment: .any)
let entity = arView.entity(at: location)

At this stage I am in need of applying the force at the point of the Tap impact. Since I am in this iteration using tap, the force is always the same (in the next iteration I want to count with the velocity/vector of the impact and push my object with greater force on greater velocity gesture).

I just want to make sure the object is behaving the right way. Is this possible?


Solution

  • I think you need the following approach.

    First of all, apply generateCollisionShapes(...) instance method that activates collisions for given entities.

    func generateCollisionShapes(recursive: Bool)
    

    Secondly, use ray(...) method returning an optional tuple:

    @MainActor func ray(through screenPoint: CGPoint) -> (origin: SIMD3<Float>, 
                                                       direction: SIMD3<Float>)?
    

    Thirdly, use arView.scene.raycast(...) method that returns CollisionCastHit collection:

           func raycast(origin: SIMD3<Float>, 
                     direction: SIMD3<Float>, 
                        length: Float = 100, 
                         query: CollisionCastQueryType = .all, 
                          mask: CollisionGroup = .all, 
    relativeTo referenceEntity: Entity? = nil) -> [CollisionCastHit]
    

    Instance of CollisionCastHit can give you 4 subproperties:

    CollisionCastHit().position
    CollisionCastHit().entity
    CollisionCastHit().distance
    CollisionCastHit().normal
    

    And at last, you already know the vector of force...

    entity.physicsMotion?.linearVelocity = SIMD3<Float>()
    

    Optionally, you might use an angular velocity of the body around the center of its mass.

    entity.physicsMotion?.angularVelocity = SIMD3<Float>()