Reputation: 3394
Calling an SCNAction from the completion handler of RunAction seems to hang SceneKit.
A touch event or rotating the device seems to unblock the hang.
To reproduce:
1) Take the default SceneKit project you get on startup with the rotating spaceship.
2) Replace the animation code:
ship.RunAction(SCNAction.RepeatActionForever(SCNAction.RotateBy(0, 2, 0, 1)));
with:
ship.RunAction(SCNAction.RotateBy(0, 2, 0, durationInSeconds: 3.0f), delegate
{
Console.WriteLine("DONE ROTATE");
ship.RunAction(SCNAction.MoveBy(1, 0, 0, durationInSeconds: 3.0f), delegate
{
Console.WriteLine("DONE MOVEBY");
});
});
3) Run on the simulator or real device (the problem is the same on both)
4) The results is:
Spaceship rotates OK
DONE ROTATE is printed out OK
Now it's hung
Tap the screen (or rotate the device to landscape) and then the move happens OK and DONE MOVEBY is printed out.
I'm using C# and Visual Studio for Mac, but I suspect it happens using Xcode too.
Is this a bug in SceneKit? How can a workaround be done?
Maybe this is the same issue as described here:
SCNAction completion handler awaits gesture to execute
Upvotes: 0
Views: 887
Reputation: 1611
My solution is to use DispatchQueue to lunch inner actions:
piece.runAction(action0, completionHandler: {
DispatchQueue.main.asyncAfter(deadline: .now()) {
ship.runAction(action1)
}
}
Upvotes: 0
Reputation: 3394
Using SCNTransaction with a completionBlock does not suffer from the same problem, so this works fine:
SCNTransaction.Begin();
SCNTransaction.AnimationDuration = 3.0f;
SCNTransaction.SetCompletionBlock(() =>
{
Console.WriteLine("DONE ROTATE");
SCNTransaction.Begin();
SCNTransaction.AnimationDuration = 3.0f;
SCNTransaction.SetCompletionBlock(() =>
{
Console.WriteLine("DONE MOVEBY");
});
ship.Position = new SCNVector3(1.0f, 0.0f, 0.0f);
SCNTransaction.Commit();
});
ship.EulerAngles = new SCNVector3(0.0f, (float)Math.PI / 2, 0.0f);
SCNTransaction.Commit();
(Also using CABasicAnimation with CAAnimationDelegate to do the callback works OK.)
Since SCNTransaction and CABasicAnimation work, but RunAction doesn't, it really looks like an Apple bug in RunAction.
Upvotes: 1
Reputation: 746
This happens because by default SceneKit is not rendering continuously. When tapping the screen the scene is changed and a new frame will be rendered. That's why the moveBy
action is not triggered immediately after the rotateBy
action.
Try setting SCNView
's renderContinuously
property to true like so:
scnView.rendersContinuously = true
ship.runAction(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 3.0)) {
print("DONE ROTATE")
ship.runAction(SCNAction.moveBy(x: 1, y: 0, z: 0, duration: 3.0), completionHandler: {
print("DONE MOVEBY")
scnView.rendersContinuously = false
})
}
Upvotes: 3