I found a solution - it's because I had to play the 2nd animation after the 1st animation is done. Luckily, I already have a custom RLCallbackAction and RLWaitAction handy for this purpose. Something like this:
struct RLAggregationActionImpl: RLActionImpl {
enum Aggregation {
case group
case sequence
}
let actions: [any RLActionImpl]
let aggregation: Aggregation
func createAnimation(entity: RLEntity) -> RLAnimation {
switch aggregation {
case .group:
let animations = actions.map { $0.createAnimation(entity: entity) }
return try! .group(with: animations)
case .sequence:
let animations = actions
.enumerated()
.flatMap { (i, impl) -> [RLAnimation] in
// We can't directly pass the action to .sequence
// Because 2 transform actions don't "Add up", likely because the animation is "inflated" when we call `entity.playAnimation`.
// As a workaround, we have to wrap it under a callback action, which calls `runAction` when it actually needs to run the action in the sequence.
// See: https://stackoverflow.com/questions/79716776/in-realitykit-a-sequence-of-2-fromtobyaction-does-not-add-up-transforms
let callback = RLCallbackActionImpl(duration: 0, callback: { $0.runActionImpl(impl) })
.createAnimation(entity: entity)
// callback happens immediately, but runAction will take duration to complete. So we need to insert a "gap" (wait action) between callbacks.
if i+1 < actions.count {
let wait = RLWaitActionImpl(duration: impl.duration)
.createAnimation(entity: entity)
return [callback, wait]
} else {
return [callback]
}
}
return try! .sequence(with: animations)
}
}
}