在 SceneKit 游戏中为 SCNNode 设置动画 SCNConstraint (LookAt) 以使过渡渐进
Animating SCNConstraint (LookAt) for SCNNode in SceneKit game to make the transition gradual
一般来说,当一个人想要让游戏中的角色面对相机时,可以使用SCNLookAtConstraint,这对我来说也很有用。
下面,my_object 是我试图根据约束确定方向的节点。 'Enemy'指的是场景中的某个节点,pointOfView是场景的View点。当我点击 my_object 时,它应该会注视敌人一秒钟,然后回到我的 pointOfView。
设置 LookAtConstraint 以便 'object' 查看 'enemy' 一秒钟。
my_object.constraints?.removeAll()
let targetNode = sceneView.scene.rootNode.childNode(withName: (chosenScenarioForChallenge?.shape)!, recursively: true)
let lookAt = SCNLookAtConstraint(target: targetNode)
lookAt.isGimbalLockEnabled = true
my_object.constraints = [lookAt]
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(resetObject), userInfo: nil, repeats: false)
Resetting object 看'enemy'节点后我的观点
@objc
func resetObject() {
my_object.constraints?.removeAll()
let targetNode = sceneView.pointOfView
let lookAt = SCNLookAtConstraint(target: targetNode)
lookAt.isGimbalLockEnabled = true
my_object.constraints = [lookAt]
}
我的问题是,我不想突然改变约束。我希望它流畅,因此我想在其中加入动画。在查看了 SCNAction 和 SCNAnimation 之后,我没有找到任何与约束相关的内容。由于约束动态更新位置,我可以理解 SCNAction.move(to/ by:) 等将不起作用。最终,当我点击时,我的对象应该开始逐渐注视敌人节点,在 1-2 秒后,它应该会逐渐返回查看我的 pointOfView。
请注意,我不希望角色从技术上看镜头,因此我使用的是 SCNLookAtConstraint,而不是 SCNBillboardConstraint。
指针会有所帮助,TIA。
target
属性 是可读写的,因此您应该能够重用 SCNLookAtConstraint
实例(而不是创建一个新实例)并仅交换目标。
编辑
约束的 influenceFactor
允许在节点的当前变换和约束计算的变换之间实现更平滑的动画。
基于测试@Managanese 的答案,我可以说 它有效 ,不知何故 influenceFactor 和 animationDuration 携手并进。我真的不明白,为什么 influenceFactor 的设置是必要的,它应该没有,但不知何故,它是。
我为其他遇到问题的人展示了一个代码示例(Swift 5.0,Xcode 11.2):
private func smoothlyLookAtTarget() {
// influenceFactor and animationDuration work somehow together
let constraint = SCNLookAtConstraint(target: targetNode)
constraint.isGimbalLockEnabled = true
constraint.influenceFactor = 0.1
SCNTransaction.begin()
SCNTransaction.animationDuration = 3.0
cameraNode.constraints = [constraint]
SCNTransaction.commit()
}
另一种方法是使用外观约束将摄像机锁定到 cameraTargetNode,然后通过动画移动该节点,甚至在该节点上设置约束以保持与 target.position 的距离或复制 target.position。通过这种方式,您可以将对相机约束的影响设置为合适的软糖值。相机在其整个生命周期中保持其约束,您可以 enable/disable 随意。
这种方法的另一个好处是调试。您可以在开发期间为 cameraTargetNode 提供您选择的几何形状并跟踪相机目标,而无需推断或感受实际目标是什么。
我更进一步,使用 cameraMovementNode,在 cameraNode 上设置了距离和加速度约束,让我可以看到外观和运动节点的位置。影响因子和 isEnabled 在这里也很有用,因为您可以调整影响或禁用约束并单独保留约束目标。有时我注意到设置目标、changing/setting 约束甚至将相机移入和移出树形图会导致奇怪的旋转和自旋。
通过我的方法,您可以将外观或目标移动到场景中的其他 children,而不会出现任何奇怪的行为。通过这种方式,您可以通过 action/transaction 移动 moveMode,完成后,将其添加为目标的 child 并跟随和旋转目标。此外,reset() 可以处理从这些相机辅助节点清除约束,并根据需要将它们移动到场景的根部。
一般来说,当一个人想要让游戏中的角色面对相机时,可以使用SCNLookAtConstraint,这对我来说也很有用。
下面,my_object 是我试图根据约束确定方向的节点。 'Enemy'指的是场景中的某个节点,pointOfView是场景的View点。当我点击 my_object 时,它应该会注视敌人一秒钟,然后回到我的 pointOfView。
设置 LookAtConstraint 以便 'object' 查看 'enemy' 一秒钟。
my_object.constraints?.removeAll()
let targetNode = sceneView.scene.rootNode.childNode(withName: (chosenScenarioForChallenge?.shape)!, recursively: true)
let lookAt = SCNLookAtConstraint(target: targetNode)
lookAt.isGimbalLockEnabled = true
my_object.constraints = [lookAt]
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(resetObject), userInfo: nil, repeats: false)
Resetting object 看'enemy'节点后我的观点
@objc
func resetObject() {
my_object.constraints?.removeAll()
let targetNode = sceneView.pointOfView
let lookAt = SCNLookAtConstraint(target: targetNode)
lookAt.isGimbalLockEnabled = true
my_object.constraints = [lookAt]
}
我的问题是,我不想突然改变约束。我希望它流畅,因此我想在其中加入动画。在查看了 SCNAction 和 SCNAnimation 之后,我没有找到任何与约束相关的内容。由于约束动态更新位置,我可以理解 SCNAction.move(to/ by:) 等将不起作用。最终,当我点击时,我的对象应该开始逐渐注视敌人节点,在 1-2 秒后,它应该会逐渐返回查看我的 pointOfView。
请注意,我不希望角色从技术上看镜头,因此我使用的是 SCNLookAtConstraint,而不是 SCNBillboardConstraint。
指针会有所帮助,TIA。
target
属性 是可读写的,因此您应该能够重用 SCNLookAtConstraint
实例(而不是创建一个新实例)并仅交换目标。
编辑
约束的 influenceFactor
允许在节点的当前变换和约束计算的变换之间实现更平滑的动画。
基于测试@Managanese 的答案,我可以说 它有效 ,不知何故 influenceFactor 和 animationDuration 携手并进。我真的不明白,为什么 influenceFactor 的设置是必要的,它应该没有,但不知何故,它是。
我为其他遇到问题的人展示了一个代码示例(Swift 5.0,Xcode 11.2):
private func smoothlyLookAtTarget() {
// influenceFactor and animationDuration work somehow together
let constraint = SCNLookAtConstraint(target: targetNode)
constraint.isGimbalLockEnabled = true
constraint.influenceFactor = 0.1
SCNTransaction.begin()
SCNTransaction.animationDuration = 3.0
cameraNode.constraints = [constraint]
SCNTransaction.commit()
}
另一种方法是使用外观约束将摄像机锁定到 cameraTargetNode,然后通过动画移动该节点,甚至在该节点上设置约束以保持与 target.position 的距离或复制 target.position。通过这种方式,您可以将对相机约束的影响设置为合适的软糖值。相机在其整个生命周期中保持其约束,您可以 enable/disable 随意。
这种方法的另一个好处是调试。您可以在开发期间为 cameraTargetNode 提供您选择的几何形状并跟踪相机目标,而无需推断或感受实际目标是什么。
我更进一步,使用 cameraMovementNode,在 cameraNode 上设置了距离和加速度约束,让我可以看到外观和运动节点的位置。影响因子和 isEnabled 在这里也很有用,因为您可以调整影响或禁用约束并单独保留约束目标。有时我注意到设置目标、changing/setting 约束甚至将相机移入和移出树形图会导致奇怪的旋转和自旋。
通过我的方法,您可以将外观或目标移动到场景中的其他 children,而不会出现任何奇怪的行为。通过这种方式,您可以通过 action/transaction 移动 moveMode,完成后,将其添加为目标的 child 并跟随和旋转目标。此外,reset() 可以处理从这些相机辅助节点清除约束,并根据需要将它们移动到场景的根部。