拖动围绕固定点旋转节点 [英] Drag Rotate a Node around a fixed point

查看:31
本文介绍了拖动围绕固定点旋转节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个类似于 这个问题.到目前为止,我已经有了投掷能力,使用效果很好的 UIPanGestureRecognizer 在物理体上添加角脉冲.我还可以通过触摸停止旋转.

I'm trying to create a spinable node similar to the "prize wheel" in this question. So far I have the flinging capability, adding angular impulses on a physics body using a UIPanGestureRecognizer that works really well. I can also stop the spinning using a touch.

现在我尝试允许使用拖动或滑动手势对滚轮进行微调,因此如果玩家对他们最终得到的结果不满意,他们可以手动旋转/拖动/旋转它到他们喜欢的旋转方向.

Now I'm trying to allow fine adjustment of the wheel using a drag or swipe gesture so if the player isn't happy with what they end up with they can manually spin/drag/rotate it to their favoured rotation.

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

Currently I save the location of the touch in the touchesBegan and try to increment the zRotation of my node in the update loop.

旋转不跟随我的手指并且生涩.我不确定我是否对手指运动获得了足够准确的读数,或者手指的变化位置是否没有被准确地转换为弧度.我怀疑检测触摸然后在更新中处理它不是一个很好的解决方案.

The rotation doesn't follow my finger and is jerky. I'm not sure if I'm getting an accurate enough read on the finger movement or if the change position of the finger isn't being accurately translated into radians. I suspect detecting the touch and then dealing with it in the update isn't a great solution.

这是我的代码.

    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
        }
    }
}

我在更新中的多行中传播了一些数学知识,以使调试更容易.

I've spread some of the maths across multiple lines in the update to make debugging a bit easier.

如果需要,我可以添加 PanGestureRecognizer 代码,但我现在会尽量保持简短.

I can add the PanGestureRecognizer code if needed but I'll try to keep it short for now.

编辑这是我基于 GilderMan 推荐的最新代码.我认为它工作得更好,但旋转远非平稳.它以较大的增量跳跃并且不能很好地跟随手指.这是否意味着我的角度计算有问题?

EDIT Here is my latest code based on GilderMan's recommendation. I think it's working better but the rotation is far from smooth. It's jumping in large increments and not following the finger well. Does this mean there's something wrong with my angle calculation?

    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
        }
    }
}

推荐答案

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

The following code simulates a prize wheel that spins based on touch. As the user's finger moves, the wheel rotates proportionately to the speed of the finger. When the user swipes on the wheel, the wheel will spin proportionately to the velocity of the swipe. You can change the angularDamping property of the physics body to slow or increase the rate at which the wheel comes to a stop.

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
    }
}

这篇关于拖动围绕固定点旋转节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆