Reputation: 31
I can't figure out how to have the move function below repeat in order to create a constant rotation on a simple meshResource. Any suggestions?
var transform = sphereEntity.transform
transform.rotation = simd_quatf(angle: .pi, axis: [0,1,0])
let anim = sphereEntity.move(to: transform, relativeTo: sphereEntity.parent, duration: 5.0)
Upvotes: 3
Views: 1104
Reputation: 58103
.move()
instance method starts working when it's placed after the line entity added to a scene.
let boxEntity = ModelEntity(mesh: .generateBox(size: 1.0),
materials: [SimpleMaterial()])
var transform = boxEntity.transform
transform.rotation = simd_quatf(angle: .pi, axis: [0, 1, 0])
let boxAnchor = AnchorEntity()
boxAnchor.children.append(boxEntity)
arView.scene.anchors.append(boxAnchor)
boxEntity.move(to: transform, relativeTo: nil, duration: 5.0)
At the moment (December 23, 2022) all RealityKit's
.move()
methods still can't loop.
Upvotes: 1
Reputation: 746
Looping an animation is possible by subscribing to the AnimationEvents.PlaybackCompleted
event.
You'll have to move your animation logic into a separate function which you call once. Inside this function you subscribe to the PlaybackCompleted
event. When this event is fired you call the same animation function.
You can subscribe to AnimationEvents
by using the Scene.subscribe()
method:
func subscribe<E>(to event: E.Type,
on sourceObject: EventSource? = nil,
_ handler: @escaping (E) -> Void) -> Cancellable where E : Event
Please note that you'll have to import the Combine framework to be able to use this:
import Combine
The animation function then looks like this:
// This needs to be an instance variable, otherwise it'll
// get deallocated immediately and the animation won't start.
var animUpdateSubscription: Cancellable?
func animate(entity: HasTransform,
angle: Float,
axis: SIMD3<Float>,
duration: TimeInterval,
loop: Bool)
{
var transform = entity.transform
// We'll add the rotation to the current rotation
transform.rotation *= simd_quatf(angle: angle, axis: axis)
entity.move(to: transform, relativeTo: entity.parent, duration: duration)
// Checks if we should loop and if we have already subscribed
// to the AnimationEvent. We only need to do this once.
guard loop,
animUpdateSubscription == nil
else { return }
animUpdateSubscription = scene.subscribe(to: AnimationEvents.PlaybackCompleted.self,
on: entity,
{ _ in
self.animate(entity: entity,
angle: angle,
axis: axis,
duration: duration,
loop: loop)
})
}
Now you can call this function once to trigger a looped animation:
animate(entity: entity,
angle: angle,
axis: axis,
duration: duration,
loop: loop)
Upvotes: 1