如何用一根手指旋转SpriteNode“触摸并拖动”

时间:2018-03-24 01:59:07

标签: ios swift sprite-kit skspritenode swift4.1

如何用一根手指“触摸并拖动”旋转SpriteNode,以便:

  • 它不会蠢蠢欲动
  • 它移动了一圈(我已经多次成功完成了这个部分 - 无论是仅使用代码的解决方案还是使用SKS文件)
  • 它产生一个有意义的值(作为一个物理控制旋钮)
  • 当我的手指在它上面时它移动但在我的手指关闭时移动

我尝试过的事情:

使用CGAffineTransform的 CGAffineTransformMakeRotation 来实现SpriteKit旋钮的旋转。但我无法弄清楚如何在SpriteNode上使用CGAffineTransformMakeRotation。我可以将一种不同类型的对象放入我的场景或顶部,但那是不对的。

例如, Matthijs Hollemans'MHRotaryKnob https://github.com/hollance/MHRotaryKnob 。我将Hollemans旋钮从Objective C转换为Swift 4,但是在SpriteKit中使用它来旋转精灵时遇到了麻烦。我没有得到,因为我无法弄清楚如何在Swift中使用SpriteKit knobImageView.transform = CGAffineTransformMakeRotation (newAngle * M_PI/180.0);。我知道我可以使用Hollemans Objective C类并在我的场景顶部推动UIImage,但这似乎不是最好也不是最优雅的解决方案。

我还将 Wex 的解决方案从Objective C转换为Swift Rotate image on center using one finger touch 使用 Allan Weir 关于处理代码https://stackoverflow.com/a/41724075/1678060的CGAffineTransform部分的建议但是这不起作用。

我已尝试直接在我的精灵上设置 zRotation 而不使用.physicalBody无效。它具有相同的生涩运动,不会停在您想要停止的位置。并且当你按下' - '在弧度角前。

我还在Stack Overflow上尝试了 0x141E 的解决方案: Drag Rotate a Node around a fixed point这是使用.sks文件在下面发布的解决方案(稍微修改过 - 我已经尝试了 un - 修改版本,但并不是更好)。这种解决方案在周围晃动,不能顺利地跟随我的手指,不能始终将旋钮移动到特定点。如果我设置physicsBody属性来创建摩擦,质量或angularDamping和linearDamping或降低SKSpriteNode的速度无关紧要。

我还在互联网上搜索使用SpriteKit在Swift 4中寻找一个好的解决方案,但到目前为止无济于事。

import Foundation
import SpriteKit

class Knob: SKSpriteNode
{
    var startingAngle: CGFloat?
    var currentAngle: CGFloat?
    var startingTime: TimeInterval?
    var startingTouchPoint: CGPoint?

    override init(texture: SKTexture?, color: UIColor, size: CGSize) {
        super.init(texture: texture, color: color, size: size)
        self.setupKnob()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setupKnob()
    }
    func setupKnob() {
        self.physicsBody = SKPhysicsBody(circleOfRadius: CGFloat(self.size.height))
        self.physicsBody?.pinned = true
        self.physicsBody?.isDynamic = true
        self.physicsBody?.affectedByGravity = false
        self.physicsBody?.allowsRotation = true
        self.physicsBody?.mass = 30.0
        //self.physicsBody?.friction = 0.8
        //self.physicsBody?.angularDamping = 0.8
        //self.physicsBody?.linearDamping = 0.9
        //self.speed = 0.1

        self.isUserInteractionEnabled = true
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in:self)
            let node = atPoint(location)
            startingTouchPoint = CGPoint(x: location.x, y: location.y)
            if node.name == "knobHandle" {
                let dx = location.x - node.position.x
                let dy = location.y - node.position.y
                startingAngle = atan2(dy, dx)
            }
        }
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches{
            let location = touch.location(in:self)
            let node = atPoint(location)
            guard startingAngle != nil else {return}
            if node.name == "knobHandle" {
                let dx:CGFloat = location.x - node.position.x
                let dy:CGFloat = location.y - node.position.y
                var angle: CGFloat = atan2(dy, dx)

                angle = ((angle) * (180.0 / CGFloat.pi))
                let rotate = SKAction.rotate(toAngle: angle, duration: 2.0, shortestUnitArc: false)
                self.run(rotate)

                startingAngle = angle
            }
        }
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        var touch: UITouch = touches.first!
        var location: CGPoint = touch.location(in: self)

        self.removeAllActions()
        startingAngle = nil
        startingTime = nil
    }
}

编辑:如果我将转换移至度数并在SKAction.rotate(toAngle:duration: 1.0, shortestUnitArc:)中将SKAction的持续时间更改为1.0,那么它几乎可以正常工作:不是 as 生涩,但仍然是混蛋;杠杆并没有很好地改变方向 - 有时如果你试图将它移动到它正在行进的方向的对面,它继续沿着锚点的旧方向而不是你拖动它的新方向。

编辑2: GreatBigBore 我讨论了SKAction轮换和self.zRotation-上面的代码和下面的代码。

编辑3: sicvayne 为SKScene建议了一些代码,我已经适应了SKSpriteNode(下面)。它不会一直移动或允许您在特定的地方停留。

import Foundation
import SpriteKit

class Knob: SKSpriteNode {

    var fingerLocation = CGPoint()

    override init(texture: SKTexture?, color: UIColor, size: CGSize) {
        super.init(texture: texture, color: color, size: size)
        self.setupKnob()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setupKnob()
    }
    func setupKnob() {
        self.isUserInteractionEnabled = true
    }
    func rotateKnob(){
        let radians = atan2(fingerLocation.x - self.position.x, fingerLocation.y - self.position.y)
        self.zRotation = -radians
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
        }
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {

            fingerLocation = touch.location(in: self)
        }
        self.rotateKnob()
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    }
    /*override func update(_ currentTime: TimeInterval) { //this is a SKScene function
     rotateKnob()
     }*/
}

2 个答案:

答案 0 :(得分:2)

我通常做这样的事情,没有任何抖动或抽搐问题。

$('#defaultPopup').datepick({
onChangeMonthYear: function(year, month, inst) {
            var changed_date = $.datepick.formatDate('MM', new Date(month+'.01.'+year));
            $('.datepick a.datepick-cmd-today').html(changed_date);
            console.log(changed_date); //works
        },
}); 

根据图像的面对方式,您可能不得不使用弧度。在我的情况下,我的&#34;播放器&#34;图像朝上。希望这有帮助。

答案 1 :(得分:2)

数学错了。以下是我学到的所需内容: Mathematical formula for getting angles

这看起来如何迅速:

if point.x.sign == .minus {
    angle = atan(point.y/point.x) + CGFloat.pi/2
} else {
    angle = atan(point.y/point.x) + CGFloat.pi/2 + CGFloat.pi
}

此外,您必须获取场景中另一个对象的坐标,因为整个坐标系随对象一起旋转:

let body = parent?.childNode(withName: "objectInScene")
let point = touch.location(in: body!)