Swift 拖动并围绕固定点旋转节点

Swift 拖动并围绕固定点旋转节点,swift,sprite-kit,Swift,Sprite Kit,我正在尝试创建一个类似于中“奖赏轮”的可旋转节点。到目前为止,我已经具备了投掷能力,使用UIPangestureRecognitor在物理物体上添加角度脉冲,该识别器工作得非常好。我还可以通过触摸停止旋转 现在,我尝试使用拖动或滑动手势来微调轮子,这样,如果玩家对最终的结果不满意,他们可以手动旋转/拖动/旋转轮子到他们喜欢的旋转方向 目前,我将触摸的位置保存在touchsbegind中,并尝试在更新循环中增加我的节点的zRotation 旋转不跟随我的手指,而且是不平稳的。我不确定我是否获得了足

我正在尝试创建一个类似于中“奖赏轮”的可旋转节点。到目前为止,我已经具备了投掷能力,使用UIPangestureRecognitor在物理物体上添加角度脉冲,该识别器工作得非常好。我还可以通过触摸停止旋转

现在,我尝试使用拖动或滑动手势来微调轮子,这样,如果玩家对最终的结果不满意,他们可以手动旋转/拖动/旋转轮子到他们喜欢的旋转方向

目前,我将触摸的位置保存在touchsbegind中,并尝试在更新循环中增加我的节点的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
        }
    }
}

SKNode
zRotation
以弧度为单位。您可以删除对度的转换


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

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

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
    }
}
class游戏场景:SKScene{
var启动角度:CGFloat?
var启动时间:时间间隔?
覆盖func didMove(到视图:SKView){
let wheel=SKSpriteNode(图像名为“宇宙飞船”)
wheel.name=“车轮”
车轮调整刻度(0.5)
wheel.physicsBody=SKPhysicsBody(圆环半径:wheel.size.width/2)
//根据需要更改此属性(将其增大以加快速度)
车轮。物理车身!。角度阻尼=0.25
wheel.physicsBody?.pinted=真
轮子。物理体?。受重力影响=假
addChild(车轮)
}
覆盖func TouchesBegind(Touchs:Set,带有事件:UIEvent?){
接触{
让位置=触摸。位置(in:self)
让节点=点(位置)
如果node.name==“控制盘”{
设dx=location.x-node.position.x
设dy=location.y-node.position.y
//存储角度和当前时间
起动角度=atan2(dy,dx)
startingTime=touch.timestamp
node.physicsBody?.angularVelocity=0
}
}
}
覆盖功能触摸移动(touchs:Set,带有事件:UIEvent?){
接触{
让位置=触摸。位置(in:self)
让节点=点(位置)
如果node.name==“控制盘”{
设dx=location.x-node.position.x
设dy=location.y-node.position.y
让角度=atan2(dy,dx)
//计算角速度;在pi/-pi处处理包裹
var deltaAngle=角度-启动角度!
如果abs(deltaAngle)>CGFloat.pi{
如果(三角洲角度>0){
deltaAngle=deltaAngle-CGFloat.pi*2
}
否则{
deltaAngle=deltaAngle+CGFloat.pi*2
}
}
设dt=CGFloat(touch.timestamp-startingTime!)
let速度=三角洲角/dt
节点.physicsBody?.angularVelocity=速度
//更新角度和时间
起始角度=角度
startingTime=touch.timestamp
}
}
}
覆盖函数touchesend(touchs:Set,带有事件:UIEvent?){
起动角=零
启动时间=零
}
}

谢谢,我会尝试一下,谢谢你的建议!这比我所取得的成绩要近得多,但仍然不能很好地跟踪手指,我想我的角度计算必须关闭。我也有点担心,很明显,MostTrecentTouchLocation可能没有做我认为它做的事情。有什么想法吗?我已经把最新的代码放在上面了。好吧,我假设你正试图让车轮边缘跟随你的手指。如果角度增加,则只需设置角度。因此类似于
node.zRotation=angle
而不是
node.zRotation+=angle
。然后它应该跟随你的手指。这似乎将精灵的旋转设置回接近0的位置(如果它是一个时钟,则在12位置)。这不是意味着我应该使用+=因为旋转很小,应该加上吗?等等,我们是在计算手指转动方向盘的位置,还是在做其他事情?你的问题似乎是用手指指向控制。对于手指代码,您可能需要在计算的角度上加上或减去
M_PI_2
(PI/2)。原始Post中的角度转换没有问题,因此atan2f结果以弧度为单位,这是添加到Z旋转的正确单位?是,
zRotation
atan2f
的单位是弧度,这太不可思议了,非常感谢!大约8点钟的时候,雪碧好像翻了个身,你看到这种行为了吗?是的,我会努力解决这个问题,非常感谢。我将花一些时间来了解这一点,以确保我完全理解它。我添加了一个检查,以确保当触摸从节点开始并继续移动时,触摸中的起始角度不为零。否则效果很好!
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
    }
}