拖动围绕固定点旋转节点

时间:2015-08-21 14:48:51

标签: swift sprite-kit

我试图创建一个类似于"奖轮"的可旋转节点。在this question。到目前为止,我具有投掷能力,使用UIPanGestureRecognizer在物理体上添加角度脉冲,效果非常好。我也可以通过触摸来停止旋转。

现在我尝试使用拖动或滑动手势对车轮进行微调,如果玩家对他们最终得到的结果不满意,他们可以手动旋转/拖动/旋转它们到他们的赞成轮换。

目前,我在touchesBegan中保存触摸的位置,并尝试在更新循环中增加节点的zRotation。

旋转不跟随我的手指而且是生涩的。我不确定我是否能够准确读取手指移动或者手指的更改位置是否准确地转换为弧度。我怀疑检测到触摸,然后在更新中处理它并不是一个很好的解决方案。

这是我的代码。

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent?) {
    if let touch = touches.first as? UITouch {
        var location = touch.locationInView(self.view)
        location = self.convertPointFromView(location)

        mostRecentTouchLocation = location

        let node = nodeAtPoint(location)
        if node.name == Optional("left") && node.physicsBody?.angularVelocity != 0
        {
            node.physicsBody = SKPhysicsBody(circleOfRadius:150)
            node.physicsBody?.applyAngularImpulse(0)
            node.physicsBody?.pinned = true
        }
    }
}

    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
        if mostRecentTouchLocation != CGPointZero{
        let node = nodeAtPoint(mostRecentTouchLocation)
        if node.name == Optional("left")
        {
            var positionInScene:CGPoint = mostRecentTouchLocation
            let deltaX:Float = Float(positionInScene.x) - Float(node.position.x)
            let deltaY:Float = Float(positionInScene.y) - Float(node.position.y)
            let angle:CGFloat = CGFloat(atan2f(deltaY, deltaX))
            let maths:CGFloat = angle - (CGFloat(90) * (CGFloat(M_PI) / 180.0))
            node.zRotation += maths
            mostRecentTouchLocation = CGPointZero
        }
    }
}

我在更新中将一些数学分布在多行中,以使调试更容易。

如果需要,我可以添加PanGestureRecognizer代码,但我现在试着保持简短。

修改 这是我基于GilderMan推荐的最新代码。我认为它的效果更好,但轮换远非顺畅。它以很大的增量跳跃而不是很好地跟随手指。这是否意味着我的角度计算有问题?

    override func didSimulatePhysics() {
    if mostRecentTouchLocation != CGPointZero {
        let node = nodeAtPoint(mostRecentTouchLocation)
        if node.name == Optional("left")
        {
            var positionInScene:CGPoint = mostRecentTouchLocation
            let deltaX:Float = Float(positionInScene.x) - Float(node.position.x)
            let deltaY:Float = Float(positionInScene.y) - Float(node.position.y)
            let angle:CGFloat = CGFloat(atan2f(deltaY, deltaX))
            node.zRotation += angle
            println(angle)
            mostRecentTouchLocation = CGPointZero
        }
    }
}

2 个答案:

答案 0 :(得分:8)

以下代码模拟基于触摸旋转的奖轮。当用户的手指移动时,轮子与手指的速度成比例地旋转。当用户在车轮上滑动时,车轮将按比例旋转到滑动的速度。您可以更改物理主体的angularDamping属性以减慢或增加轮子停止的速率。

class GameScene: SKScene {
    var startingAngle:CGFloat?
    var startingTime:TimeInterval?

    override func didMove(to view: SKView) {
        let wheel = SKSpriteNode(imageNamed: "Spaceship")
        wheel.name = "wheel"
        wheel.setScale(0.5)
        wheel.physicsBody = SKPhysicsBody(circleOfRadius: wheel.size.width/2)
        // Change this property as needed (increase it to slow faster)
        wheel.physicsBody!.angularDamping = 0.25
        wheel.physicsBody?.pinned = true
        wheel.physicsBody?.affectedByGravity = false
        addChild(wheel)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in:self)
            let node = atPoint(location)
            if node.name == "wheel" {
                let dx = location.x - node.position.x
                let dy = location.y - node.position.y
                // Store angle and current time
                startingAngle = atan2(dy, dx)
                startingTime = touch.timestamp
                node.physicsBody?.angularVelocity = 0
            }
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches{
            let location = touch.location(in:self)
            let node = atPoint(location)
            if node.name == "wheel" {
                let dx = location.x - node.position.x
                let dy = location.y - node.position.y

                let angle = atan2(dy, dx)
                // Calculate angular velocity; handle wrap at pi/-pi
                var deltaAngle = angle - startingAngle!
                if abs(deltaAngle) > CGFloat.pi {
                    if (deltaAngle > 0) {
                        deltaAngle = deltaAngle - CGFloat.pi * 2
                    }
                    else {
                        deltaAngle = deltaAngle + CGFloat.pi * 2
                    }
                }
                let dt = CGFloat(touch.timestamp - startingTime!)
                let velocity = deltaAngle / dt

                node.physicsBody?.angularVelocity = velocity

                // Update angle and time
                startingAngle = angle
                startingTime = touch.timestamp
            }
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        startingAngle = nil
        startingTime = nil
    }
}

答案 1 :(得分:0)

zRotation的{​​{1}}是弧度。您可以将转换移至学位。

您可能希望在SKNode中进行角度调整,以便在应用物理后计算didSimulatePhysics。 (这可能不适用于这种情况,但这是一种良好的做法。)