SpriteKit将旋转的车轮停在定义的角度

时间:2019-01-25 15:41:55

标签: ios swift sprite-kit

我使用SpriteKit实现了以角速度ω旋转的纺车,不涉及加速度。

当用户按下按钮时,我需要使车轮从当前角度∂0缓慢减速,并以指定角度结束旋转(我们称之为∂f)。

我创建了与之关联的mass中的2

我已经尝试angularDampingSKAction.rotate(toAngle: duration:) ,但它们不符合我的需求,因为:

  1. 对于angularDamping,我无法轻松指定要结束的角度∂f
  2. 使用SKAction.rotate(toAngle: duration:)时,我无法从当前旋转速度开始减速,并且运行起来也不自然。

我尝试过的唯一剩下的方法是使用SKAction.applyTorque(duration:)。 这听起来很有趣,但我在计算公式以获取要应用的正确扭矩方面遇到困难,尤其是对于车轮的惯性和半径。

这是我的方法:

  • 我将起始角速度ω设为: wheelNode.physicsBody?.angularVelocity

  • 我要从mass拿走wheelNode.physicsBody?.mass

  • 时间t10的常数(这意味着我想在10秒内将车轮减速到最终角度∂f)。

    < / li>
  • 我计算出的减速度为: let a = -1 * ω / t

  • 惯性应为:let I = 1/2 * mass * pow(r, 2) *。 (请参见有关半径的注释)

  • 然后,最后,我计算出要应用的最终扭矩为:let t = I * a(请注意,与当前车轮的角速度相反)。

注意:

由于我不清楚如何获得车轮的半径,因此我试图抓住车轮的原因是:

  1. wheelNode.physicsBody?.arealet r = sqrt(wheelNode.physicsBody?.area ?? 0 / .pi)
  2. 通过将像素area documentation says从像素转换为米。然后我有let r = self.wheelNode.radius / 150

有趣:我得到2个不同的值:(

不幸的是,这种方法无法正常工作,因为到目前为止,我仍不知道如何以指定角度结束,并且车轮始终无法按预期停止(或者扭矩过大)并朝另一个方向旋转,或者不够)。因此,施加的扭矩似乎也是错误的。


您知道实现我所需结果的更好方法吗?那是正确的方法吗?如果是,我的计算出了什么问题?

1 个答案:

答案 0 :(得分:2)

运动学使我的头部受伤,但是你去了。我到了您可以输入旋转量的位置,并且随着速度减慢到指定角度,轮子将旋转很多次。还有其他功能和扩展名可以使代码相对干净/可读。因此,如果您只想要一个巨大的混乱功能,请继续进行修改。

•确保节点的angularDampening = 0.0

•确保节点具有圆形物理体

// Stops a spinning SpriteNode at a specified angle within a certain amount of rotations
//NOTE: Node must have a circular physicsbody
// Damping should be from 0.0 to 1.0
func decelerate(node: SKSpriteNode, toAngle: CGFloat, rotations: Int) {

    if node.physicsBody == nil { print("Node doesn't have a physicsbody"); return } //Avoid crash incase node's physicsbody is nil
    var cw:CGFloat { if node.physicsBody!.angularVelocity < CGFloat(0.0) { return -1.0} else { return 1.0} } //Clockwise - using int to reduce if statments with booleans

    let m = node.physicsBody!.mass // Mass
    let r = CGFloat.squareRoot(node.physicsBody!.area / CGFloat.pi)() // Radius
    let i = 0.5 * m * r.squared // Intertia

    let wi = node.physicsBody!.angularVelocity // Initial Angular Velocity
    let wf:CGFloat = 0 // Final Angular Velocity

    let ti =  CGFloat.unitCircle(node.zRotation)  // Initial Theta
    var tf = CGFloat.unitCircle(toAngle) // Final Theta

    //Correction constant based on rate of rotation since there seems to be a delay between when the action is calcuated and when it is run
    //Without the correction the node stops a little off from its desired stop angle
    tf -= 0.00773889 * wi //Might need to change constn

    let dt = deltaTheta(ti, tf, Int(cw), rotations)

    let a = -cw * 0.5 * wi.squared / abs(dt) // Angular Acceleration - cw used to determine direction
    print("A:\(a)")
    let time:Double = Double(abs((wf-wi) / a)) // Time needed to stop
    let torque:CGFloat = i * a // Torque needed to stop

    node.run(SKAction.applyTorque(torque, duration: time))
}

func deltaTheta(_ ti:CGFloat, _ tf:CGFloat, _ clockwise: Int, _ rotations: Int) -> CGFloat {

    let extra = CGFloat(rotations)*2*CGFloat.pi

    if clockwise == -1 {
        if tf>ti { return tf-ti-2*CGFloat.pi-extra }else{ return tf-ti-extra }
    }else{
        if tf>ti { return tf-ti+extra }else{ return tf+2*CGFloat.pi+extra-ti }
    }
}

}

extension CGFloat {

public var squared:CGFloat { return self * self }

public static func unitCircle(_ value: CGFloat) -> CGFloat {
    if value < 0 { return 2 * CGFloat.pi + value }
    else{ return value }
}
}