Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pausing a SceneKit animation

I'm trying to create a test app in which the user can pause an animation by clicking in the SceneView. The SceneView loads the animation from a .dae file created in a 3d app (Cinema 4D). The app successfully plays and loops the animation upon launch.

To pause the animation, I used Technical Q&A QA1673 as a reference. In the case of this .dae file, the animation actually comes in as a hierarchy of animations, so I have tried reaching down to each underlying CAKeyframeAnimation and setting its speed to zero. My code currently looks like this:

- (void)mouseDown:(NSEvent *)event {

     SCNNode *cubeNode = [self.scene.rootNode childNodeWithName:@"C4D_Cube" recursively:YES];
     CAAnimation *cubeAnimation = [cubeNode animationForKey:@"Cube_Anim_01-02-1"];      
     CAAnimationGroup *cubeAnimationGroup = (CAAnimationGroup *)cubeAnimation;

     // cubeAnimationGroup contains 3 CAAnimationGroups, each of which contains a CAKeyframeAnimation.
     // So I directly access each CAKeyframeAnimation and set its speed to zero.
     for (CAAnimationGroup *subGroup in [cubeAnimationGroup animations]) {
          CFTimeInterval pausedTime = CACurrentMediaTime();
          [[subGroup animations] setValue:@0.0 forKey:@"speed"];
          [[subGroup animations] setValue:[NSNumber numberWithFloat:pausedTime] forKey:@"timeOffset"];
     }
}

When I set a breakpoint, I can see that the speed of the keyframe animations does change from 1 to 0, but the animation continues to play at its normal speed in the scene view. I originally tried just setting the speed on the top level CAAnimationGroup to zero, but this also had no effect. What's the correct way to pause an animation in progress?

like image 351
Jack Bransfield Avatar asked Jan 22 '26 05:01

Jack Bransfield


2 Answers

The animations returned by "animationForKey:" are copies of the running animations. The documentation says "Attempting to modify any properties of the returned object will result in undefined behavior." So you could do something like this instead:

for(NSString *key in [myNode animationKeys]){
    CAAnimation *animation = [myNode animationForKey:key];
    [animation setSpeed:0]; //freeze
    [animation setTimeOffset:CACurrentMediaTime() - [animation beginTime]]; //move back in time
    [cube addAnimation:animation forKey:key]; //re-add the animation with the same key to replace
}

Note that if you just want to pause all the animations coming from a .DAE you might want to do:

[mySCNView setPlaying:NO]; //pause scene-time based animations

like image 78
toyos Avatar answered Jan 24 '26 23:01

toyos


Or you could set paused to true.

In Swift:

mySCNView.scene?.paused = true
like image 20
Eric Avatar answered Jan 24 '26 22:01

Eric



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!