【问题标题】:SpriteKit stop spinning wheel in a defined angleSpriteKit 以定义的角度停止旋转轮子
【发布时间】:2019-01-25 15:41:55
【问题描述】:

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

当用户按下按钮时,我需要从当前角度 ∂0 缓慢减速车轮并最终到达指定角度(我们称之为 ∂f)。

我创建了一个与它相关联的 mass2

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

  1. 使用angularDamping,我无法简单地指定∂f 我想要结束的角度。
  2. 使用SKAction.rotate(toAngle: duration:),我无法从当前的旋转速度开始减慢速度,它的表现也不自然。

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

这是我的方法:

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

  • 我要从wheelNode.physicsBody?.massmass

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

  • 我计算的减速度为: 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 个不同的值 :(

不幸的是这种方法中的某些东西不起作用,因为到目前为止我不知道如何以指定的角度结束并且车轮无论如何都不会停止(或者扭矩太多向另一个方向旋转,或者还不够)。因此,施加的扭矩似乎也是错误的。


您知道实现我需要的结果的更好方法吗?这是正确的方法吗?如果是,我的计算有什么问题?

【问题讨论】:

    标签: ios swift sprite-kit


    【解决方案1】:

    运动学让我头疼,但你去吧。我做到了你可以输入旋转量的地方,当它减速到你指定的角度时,轮子会旋转很多次。其他功能和扩展是为了保持代码相对干净/可读。因此,如果您只想要一个巨大的混乱功能,请继续修改它。

    • 确保节点的 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 }
    }
    }
    

    【讨论】:

    • 我尝试了您的解决方案,但车轮似乎并不总是以相同的角度停止。我是说。假设我给函数stop 赋予.pi 的角度,我希望轮子总是以.pi 的角度停止,但似乎并非如此。问题可能出在哪里?
    • 嗯,当我使用它时,它正在按您的意愿工作。我会尽快修复它。 @A_C
    • 亲爱的@Muffinman2497 我注意到当车轮旋转得非常快时,我的实现也不精确。这可能是由于旋转车轮的 GPU 和计算物理的 CPU 之间的并行计算吗?我试图猜测。比如...当 CPU 完成计算要执行的动作时,GPU 已经稍微旋转了轮子,导致结果不精确。
    • @A_C 我修正了我的答案,所以它应该可以工作。我认为您在计算动作和运行它之间存在延迟是正确的。我在计算中添加了一个常数来弥补这一点。该常数考虑了轮速,因此增加的转速不会产生更高的误差。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多