【问题标题】:SpriteKit camera actions being very jerky/laggySpriteKit 相机动作非常生涩/滞后
【发布时间】:2017-05-20 18:45:01
【问题描述】:

我正在使用 Swift 3.0 和 Xcode 8.2.1,在运行 iOS 10.2 的 iPhone 6s 上进行测试。

我只是试图以减慢的速度旋转 SKCameraNode(即它同时具有角速度和加速度)。

这是我目前的解决方案,是的,我知道这很奇怪:

 cam.run(
    SKAction.repeatForever(
        SKAction.sequence([
            SKAction.run
                {
                    self.cam.run(SKAction.rotate(toAngle: 0.0, duration: 0.7, shortestUnitArc: true))
                },
            SKAction.wait(forDuration: 0.1)])))

相机的 zRotation 从某个非零位置开始,然后调用它。然后它每 0.1 秒调用一次 SKAction.rotate 部分。这里没有显示,但我让它在 3 秒后终止。

这提供了我想要的确切效果,因为每次调用 SKAction 时,zRotation 都更接近其 0.0,但到达那里所需的时间保持在 0.7,因此它接近 0.0 的速率放慢速度。

但是,3 件事中的 1 件由此发生:

  1. 按预期完美运行
  2. 感觉就像每 0.1 秒停止并继续一样
  3. 调用 SKAction 后,相机会立即完全停止作为相机的功能,并且玩家会一直盯着同一个位置直到相机切换。

我尝试将 waitForDuration 从 0.1 减少到 0.01,但它总是执行选项 3。

在使用相机时,我是否没有遵守某种“执行规则”?

谢谢!

【问题讨论】:

  • 0x141E 的答案对于这个特定的情况看起来不错。但如果你想要一个更好的通用动画系统,让我插入我的animation library。它允许您使用与显示刷新同步调用的闭包触发动画,您可以在其中进行计算并设置所需的任何值。例如,在您的情况下,它很简单:rotation = startAngle <~~ Curve.parabolicDeceleration[progress] ~~> 0.0<~~~~> 运算符是库的一部分,用于在两个值之间进行插值。

标签: ios swift sprite-kit skaction


【解决方案1】:

您可以使用单个rotate(toAngle:) 动作,当相机的zRotation 接近结束角度并将timingMode 属性设置为.easeOut 时减速。例如,

cam.zRotation = CGFloat.pi
let action = SKAction.rotate(toAngle: 0, duration: duration, shortestUnitArc: true)

// Slows when zRotation is near 0
action.timingMode = .easeOut

cam.run(action)

或者,您可以定义自己的计时函数来自定义缓出行为,方法是将timingMode 语句替换为

action.timingFunction = {
    time in
    // Custom ease-out, modify this as needed
    return 1-pow(1-time, 5)
 }

此外,您可以使用以下方法来计算动作的持续时间,因此无论起始角度如何(即旋转量),角速度和加速度都是一致的

let duration = TimeInterval(normalizedArcFromZero(angle:cam.zRotation)) * 3

func normalizedArcFromZero(angle:CGFloat) -> CGFloat {
    let diff = angle.mod(dividingBy:CGFloat.pi*2)
    let arc = CGFloat.pi - (diff + CGFloat.pi).mod(dividingBy:2 * CGFloat.pi)
    return abs(arc)/CGFloat.pi
}

最后,由于上述需要一个模函数来执行“下限”除法(而不是 Swift 的 truncatingRemainder),因此您需要将其添加到您的项目中

extension CGFloat {
    func mod(dividingBy x:CGFloat) -> CGFloat {
        return self - floor(self/x) * x
    }
}

【讨论】:

  • 很好的答案!一个问题——timingFunction 的输入是否会是自 SKAction 开始以来的时间?
  • @MarshallD time 从 0 开始到 1 结束。同样,闭包需要返回一个从 0 开始到 1 结束的值。如果你在我的答案中用 @987654332 绘制表达式@ 从 0 递增到 1,你会看到缓出函数的样子。然后,您可以相应地调整功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-04
  • 1970-01-01
  • 1970-01-01
  • 2012-02-22
相关资源
最近更新 更多