iosswiftrealitykit

How to implement a "CallbackAction" in RealityKit like SceneKit's SCNAction.run()?


I am converting my SceneKit game to RealityKit. One difficulty is to convert SCNAction.run. For example:

node.runAction(
  .sequence[
    .scale(to:...),
    .run { /* do something */ }
    .fadeOut(...),
    .run { /* do something else */ },
  ]
)

This is a very common pattern that exist in most game libraries (e.g. SceneKit, SpriteKit, Cocos2D, etc).

However, looking at RealityKit's action API, it looks like they only provide several basic actions such as https://developer.apple.com/documentation/realitykit/fromtobyaction

I am wondering how to support CallbackAction like in SceneKit?

It looks like Apple allows you to create your own Action but the documentation isn't great: https://developer.apple.com/documentation/realitykit/entityaction


Solution

  • Apple's doc is indeed not helpful, but I was able to get callback action working:

        struct CallbackAction: EntityAction {
          var animatedValueType: (any AnimatableData.Type)? = nil
          let callback: (Entity?) -> Void
          init(callback: @escaping (Entity?) -> Void) {
            self.callback = callback
          }
          
        }
        
        struct CallbackActionHandler: ActionHandlerProtocol {
          typealias ActionType = CallbackAction
          let action: ActionType
          let entity: Entity?
          init(action: ActionType, entity: Entity?) {
            self.action = action
            self.entity = entity
          }
          
          func actionEnded(event: EventType) {
            action.callback(entity)
          }
        }
        
    

    Before using it, make sure to register the handler. This will allow RealityKit to find the right handler when processing your action.

        CallbackActionHandler.register { event in
          return CallbackActionHandler(action: event.action, entity: event.targetEntity)
        }
    
        let callbackAction = CallbackAction { entity in
          print("callback")
        }