如何在SCNNode上实现SKAction.animate纹理动画效果?
在SCNNode上实现类似SKAction.animate的纹理逐帧动画
嘿,我完全懂你的需求——想在SceneKit的SCNNode上复刻SpriteKit里SKAction.animate(with:sprites, timePerFrame:)那种逐帧纹理动画,可惜SCNAction确实没提供现成的API。不过别担心,我们可以用自定义动作轻松实现这个效果,下面结合你的fishNode代码一步步来:
步骤1:预加载所有动画帧
首先把你需要的所有动画图片提前加载成数组,避免动画过程中临时加载导致卡顿:
func loadFishIdleFrames() -> [UIImage] { let skinIndex = GameManager.selectedFishSkin + 1 var animationFrames = [UIImage]() // 这里假设你有3帧 idle 动画,根据实际帧数量调整循环范围 for frameNumber in 1...3 { if let frameImage = UIImage(named: "fish_idle_\(frameNumber)_\(skinIndex)") { animationFrames.append(frameImage) } } return animationFrames }
步骤2:创建自定义SCNAction实现帧切换
用SCNAction.customAction来构建我们的动画逻辑,根据已流逝的时间计算当前应该显示的帧:
func createTextureAnimation(frames: [UIImage], timePerFrame: TimeInterval) -> SCNAction { let totalAnimationDuration = timePerFrame * Double(frames.count) return SCNAction.customAction(duration: totalAnimationDuration) { node, elapsedTime in // 计算当前帧的索引,取模保证循环时不会越界 let currentFrameIndex = Int(elapsedTime / timePerFrame) % frames.count // 给节点的材质切换当前帧图片 if let plane = node.geometry as? SCNPlane, let material = plane.firstMaterial { material.diffuse.contents = frames[currentFrameIndex] } } }
步骤3:给你的fishNode添加动画
最后把动画绑定到你的fishNode上,如果需要循环播放,就用repeatForever包装一下:
// 加载帧数组 let fishIdleFrames = loadFishIdleFrames() // 创建单次动画 let singleIdleLoop = createTextureAnimation(frames: fishIdleFrames, timePerFrame: 0.5) // 转为永久循环动画 let loopingIdleAnimation = SCNAction.repeatForever(singleIdleLoop) // 让节点运行动画 fishNode.runAction(loopingIdleAnimation)
额外小提示
- 如果你的动画帧数量较多,建议用
SKTextureAtlas来管理纹理,加载后取出每个SKTexture的image属性加入帧数组,这样能利用纹理集的优化,提升动画流畅度。 - 这个方法不仅适用于SCNPlane,只要你的SCNNode的几何体材质支持
diffuse.contents设置UIImage,都可以用这套逻辑实现纹理动画。
内容的提问来源于stack exchange,提问作者michael-martinez
相关产品推荐
相关产品推荐

