我正在寻找一种在 SceneKit 中制作 Sprite 表动画的方法。经过一些研究,我找到了 Core Animation 方法来执行此操作,这将是完美的,因为我需要尽可能多地控制动画。
我准备了一个简单的平面网格,其 UV 限制为一个 spritesheet 帧的大小。这样我只需要水平地设置 UV 的动画。我发现 Material 的 contentsTransform 矩阵的相关元素是 m14(负责水平平移的元素)。
但是,在运行时,SceneKit 会返回以下错误:
[SCNKit ERROR] geometry?.firstMaterial?.diffuse.contentsTransform.m14 is not an animatable path
这是相关代码:
let spritesheetAnimation = CABasicAnimation(keyPath: "geometry?.firstMaterial?.diffuse.contentsTransform.m14")
spritesheetAnimation.fromValue = 1 - 1 / spritesheetFrameCount
spritesheetAnimation.toValue = 0
spritesheetAnimation.byValue = 1 / spritesheetFrameCount
spritesheetAnimation.duration = 1.0
spritesheetAnimation.repeatCount = Float.infinity
node.geometry?.insertMaterial(material, atIndex: 0)
node.addAnimation(spritesheetAnimation, forKey: "SpritesheetAnimation")
有人有这方面的经验吗?我不知道是否有更简单的方法来做到这一点,或者我是否以错误的方式看待它或其他任何东西。因此,我们将不胜感激!
请您参考如下方法:
这里有两个问题。
CoreAnimation 将可设置动画的关键路径扩展到它可以设置动画的数据结构中——也就是说,它不仅可以在一个完整的
CATransform3D和另一个之间设置动画,还可以让您设置一个描述一些关键路径的动画转换的成员或属性(如transform.translation.x)。SceneKit 不会这样做——您只能为完整的结构值设置动画。也就是说,您只能为
contentsTransform设置动画,而不能为contentsTransform.something设置动画,为此您需要提供完整的SCNMatrix4作为>toValue/fromValue动画。KVC 键路径与 Swift 可选值没有任何关系,因此
geometry?.firstMaterial?.diffuse.contentsTransform不是合法的键路径。丢掉问号,你应该没问题。
因此,您的代码应如下所示(未经测试):
let spritesheetAnimation = CABasicAnimation(keyPath: "geometry.firstMaterial.diffuse.contentsTransform")
let translation = SCNMatrix4MakeTranslation(1 - 1 / spritesheetFrameCount, 0, 0)
spritesheetAnimation.fromValue = NSValue(SCNMatrix4: translation)
spritesheetAnimation.toValue = NSValue(SCNMatrix4: SCNMatrix4Identity)
spritesheetAnimation.duration = 1.0
spritesheetAnimation.repeatCount = .infinity
请注意,您需要将 SCNMatrix4 包装在 NSValue 中以传递给 fromValue 和 toValue,因为 Swift 不能不会像对标量数字类型那样自动转换它。
另请注意,您可以根据需要对 Float.infinity 使用类型推断。
