如何在嵌套的SCNTransaction链中添加暂停/等待



这个问题应该有一个很简单的答案,但是我找了几个小时也没有找到。除非我只需要手动添加一些计时器来等待。

基本上,我有一个动画序列将节点移动到某个位置,在这里我想等待5秒然后我有另一个动画序列将节点带回到它的原始位置。

最初,我使用SCNActions,对一些操作进行分组,然后对它们进行排序。这里我只是加了一个SCNAction.wait(duration: 5),这就成功了。然而,其中一个操作是将节点围绕x轴移动90度,并且我还需要同时围绕另一个轴旋转。结果是不正确的,我有一种感觉,我已经遇到了万向锁问题。

所以,而不是使用SCNAction.rotate(by: )我决定旋转使用四元数没有万向节锁定问题,但后来我需要切换到使用SCNTransaction。我将这些事务嵌套在前一个SCNTransaction的completionBlock中。对于两个动画之间的暂停,我在这里没有等待动作,但我认为添加一个持续时间不做任何事情的事务至少会等待同样长的时间。但事实并非如此。事务立即跳转到第三步。

那么是否有一个简单的命令告诉动画事务等待?我确实尝试添加DispatchQueue.main.asyncAfter(deadline: .now() + 5) { <3rd SCNTransaction here> },这是有效的,但这真的是这样做吗?我有一种感觉,有一些我不知道的东西取代了SCNAction.wait()

这是我当前的代码,正确地做动画,除了它不等待我想要的地方(这是相关代码的摘录):

[...]
let moveSideQuat = simd_quatf(angle: -currentYRotation, axis: simd_float3(0, 0, 1))
let moveAwaySimd = simd_float3(-20 * sinf(currentYRotation), 0, -20 * cosf(currentYRotation))
let moveUpQuat = simd_quatf(angle: .pi/2, axis: simd_float3(1, 0, 0))

let moveDownQuat = simd_quatf(angle: -.pi/2, axis: simd_float3(1, 0, 0))
let moveTowardsQuat = simd_float3(0, 0, pivotZLocation)
let moveBackSideQuat = simd_quatf(angle: currentYRotation, axis: simd_float3(0, 0, 1))
SCNTransaction.begin()
SCNTransaction.animationDuration = 1
baseNode?.simdOrientation = moveSideQuat * baseNode!.simdOrientation
baseNode?.simdPosition = moveAwaySimd
baseNode?.simdOrientation = moveUpQuat * baseNode!.simdOrientation

SCNTransaction.completionBlock = {

SCNTransaction.begin()
SCNTransaction.animationDuration = 5  // <<<--- I WANT TO WAIT HERE

SCNTransaction.completionBlock = {
SCNTransaction.begin()
SCNTransaction.animationDuration = 1
self.baseNode?.simdOrientation = moveDownQuat * self.baseNode!.simdOrientation
self.baseNode?.simdPosition = moveTowardsQuat
self.baseNode?.simdOrientation = moveBackSideQuat * self.baseNode!.simdOrientation

SCNTransaction.commit()
}

SCNTransaction.commit()
}

SCNTransaction.commit()
[...]

在第二个完成块中,在animationDuration = 5之后,我甚至试图为节点的simdPosition添加一个简单的赋值,基本上将它留在相同的位置,希望欺骗序列需要5秒基本上什么都不做,但它仍然跳到下一个completionBlock。

那么asyncAfter实际上是要走的路还是我错过了别的什么?谢谢!

使用asyncAfter等待是可以的。毕竟,这就是这个方法的目的。

创建一个持续5秒的空事务不起作用,因为SceneKit可以很容易地看到你没有改变任何东西,并且知道动画可以立即完成。你可以在场景的某个地方隐藏一个节点,并为该节点动画5秒,但这感觉更像是一种hack。

如果你想,你仍然可以使用SCNActions的其余动画,只使用SCNTransaction的那些需要四元数。例如:

let step1 = SCNAction.group([
SCNAction.run {
SCNTransaction.begin()
SCNTransaction.animationDuration = 1
// do rotations here with quaternions...
SCNTransaction.commit()
},
SCNAction.move(to: /* destination */, duration: 1)
])
let step2 = SCNAction.wait(duration: 5)
let step3 = SCNAction.group([
SCNAction.run {
SCNTransaction.begin()
SCNTransaction.animationDuration = 1
// rotate back...
SCNTransaction.commit()
},
SCNAction.move(to: /* origin */, duration: 1)
])
let entireAction = SCNAction.sequence([
step1, step2, step3
])

最新更新