SceneKit中基于时间变量计算正弦值实现立方体乒乓运动失败求助
搞定SceneKit立方体的X轴乒乓运动!
嘿,我看了你遇到的问题,还有你提供的动图——当前立方体只做了单向位移,完全没达到你想要的来回乒乓效果对吧?问题出在你对SceneKit动画的用法理解错啦!
问题根源
你现在的代码里,sin(t)*5的t是创建动画那一瞬间的时间,所以这个目标位置是固定死的!动画的作用只是让立方体用60秒慢慢挪到这个固定点,重复执行的时候,立方体已经在目标位置了,自然就不会动了,更别说乒乓来回了。
正确的两种实现方案
方案1:用SCNAction自定义动作(推荐)
SCNAction的自定义动作可以让你在动画的每一帧,根据已经流逝的时间动态计算位置,完美适配正弦运动的需求:
override func awakeFromNib() { super.awakeFromNib() // 先定义一个单个周期的自定义动作,比如2秒完成一次来回 let singleCycleAction = SCNAction.customAction(duration: 2.0) { node, elapsedTime in // elapsedTime是当前周期内已经过的时间(0到2秒) // 用2π*elapsedTime/周期时长,生成0到2π的角度,实现完整的正弦周期 let xPos = sin(2 * .pi * elapsedTime / 2.0) * 5 node.position = SCNVector3(x: xPos, y: 0, z: 0) } // 让这个动作无限重复 let pingPongAction = SCNAction.repeatForever(singleCycleAction) // 给立方体挂上这个动作 cube.runAction(pingPongAction) }
你可以调整duration:2.0来改变运动的快慢,调整*5来改变来回移动的幅度,非常灵活。
方案2:用CADisplayLink实时刷新
如果需要更精细的时间控制,也可以绑定屏幕刷新帧,实时计算位置:
private var displayLink: CADisplayLink? private var startTimestamp: CFTimeInterval? override func awakeFromNib() { super.awakeFromNib() // 记录动画开始的时间点 startTimestamp = CACurrentMediaTime() // 创建DisplayLink,绑定刷新回调 displayLink = CADisplayLink(target: self, selector: #selector(updateCubePos)) displayLink?.add(to: .main, forMode: .common) } @objc private func updateCubePos() { guard let startTime = startTimestamp else { return } let totalElapsed = CACurrentMediaTime() - startTime // 同样用正弦函数计算位置,周期2秒,幅度5 let xPos = sin(2 * .pi * totalElapsed / 2.0) * 5 cube.position = SCNVector3(x: xPos, y: 0, z: 0) } // 记得在页面消失时销毁DisplayLink,避免内存泄漏 override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) displayLink?.invalidate() displayLink = nil }
再唠唠你原代码的问题
再看你原来的代码片段:
let t = CACurrentMediaTime() animation.toValue = NSValue(SCNVector3: SCNVector3(x: CGFloat(sin(t)*5), y: CGFloat(0), z: CGFloat(0))) animation.duration = 60 animation.repeatCount = MAXFLOAT cube.addAnimation(animation, forKey: nil)
这里的t是你点击运行、创建动画那一刻的时间,比如假设这一刻t对应的sin(t)是0.8,那目标位置就是X=4,动画会让立方体用60秒慢慢挪到X=4,之后重复动画时,立方体已经在X=4了,所以就不动了——这就是为什么你只看到单向位移的原因!
内容的提问来源于stack exchange,提问作者dàhóngpáo
相关产品推荐
相关产品推荐

