iosswiftrealitykit

How to run multiple RealityKit actions concurrently like in SceneKit?


I am translating my SceneKit app to RealityKit. In SceneKit I can run multiple actions concurrently or in sequence (e.g. running both translateTo and scaleTo together). I am wondering how I can do so in RealityKit. I have the following:

let translateAction = FromToByAction<Transform>(
      from: Transform(translation: [0.0, 2.0, 0.0]),
      to: Transform(translation: [0.0, -2.0, 0.0]),
      mode: .parent,
      timing: .linear,
      isAdditive: true)
let translateAnimation = try! AnimationResource
      .makeActionAnimation(
        for: translateAction,
        duration: 5.0,
        bindTarget: .transform)
box.playAnimation(translateAnimation)
    
let scaleAction = FromToByAction(
      from: Transform(scale: SIMD3(0.5, 0.5, 0.5)),
      to: Transform(scale: SIMD3(2.5, 2.5, 2.5)),
      mode: .local,
      timing: .linear,
      isAdditive: true)
let scaleAnimation = try! AnimationResource
      .makeActionAnimation(
        for: scaleAction,
        duration: 10,
        bindTarget: .transform)
box.playAnimation(scaleAnimation)

However, it only runs the scaleAnimation, not the translationAnimation. Probably because they both bind to .transform target, so the 2nd one overwrites the 1st one. I am wondering how to solve this problem.


Solution

  • The good news is that you can use the .group(with:) type method to simultaneously play multiple primitive's transform animations. The bad news is that in RealityKit's actual version doesn't currently work a simultaneous playback of multiple skeletal animations.

    import SwiftUI
    import RealityKit
    
    struct ContentView : View {
        let box = ModelEntity(mesh: .generateBox(size: 0.25))
    
        var body: some View {
            RealityView { rvc in
                let translateAction = FromToByAction<Transform>(
                    from: .init(translation: [0.0, 1.0, 0.0]),
                    to: .init(translation: [0.0,-1.0, 0.0]),
                    mode: .local,
                    timing: .easeInOut,
                    isAdditive: true
                )
                let translate = try! AnimationResource.makeActionAnimation(
                    for: translateAction,
                    duration: 2.0,
                    bindTarget: .transform
                )
                let scaleAction = FromToByAction(
                    from: .init(scale: .one / 10),
                    to: .init(scale: .one * 4),
                    mode: .local,
                    timing: .easeInOut,
                    isAdditive: true
                )
                let scale = try! AnimationResource.makeActionAnimation(
                    for: scaleAction,
                    duration: 2.0,
                    bindTarget: .transform
                )
                let simultaneously = try! AnimationResource.group(
                    with: [translate, scale]
                )
                box.playAnimation(simultaneously)
                rvc.add(box)
            }
            .ignoresSafeArea()
            .background(.black)
        }
    }