以有限的旋转速度触摸旋转精灵

Anc*_*inu 6 rotation ios sprite-kit skaction swift

我试图让我的spriteNode旋转手指触摸.

到目前为止,我可以做到,但我想要的是我的节点具有"旋转速度".所以我计算角度的长度然后设置一个不同的时间与它一起旋转(如果弧很长,则需要时间......).

这是我的代码:

override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
    _isTouched = true
    for touch in touches {
        let location:CGVector = touch.locationInNode(self) - miner.position

        miner.weaponRotation = location.angle() - CGFloat(M_PI_2)
    }
}

var wantedRotation: CGFloat {
    get { return _wantedRotation }
    set(rotation) {
        if rotation > CGFloat(M_PI) || rotation < -CGFloat(M_PI) {
            _wantedRotation = CGFloat(M_PI) + rotation % CGFloat(M_PI)
        }
        else {
            _wantedRotation = rotation
        }

        removeActionForKey("rotation")
        let arc: CGFloat = CGFloat(abs(_wantedRotation - zRotation))
        let shortestArc: CGFloat = min(arc, CGFloat(M_PI * 2.0) - arc)
        runAction(SKAction.rotateToAngle(_wantedRotation, duration: NSTimeInterval(shortestArc / CGFloat(M_PI) * rotationSpeed), shortestUnitArc: true), withKey: "rotation")
    }
}
Run Code Online (Sandbox Code Playgroud)

主要问题是向SKAction节点添加几个阻止移动.

我想知道什么是解决方案?如果可能的话,使用SKAction,因为我想避免对每个帧进行更新以计算移动(但如果它是唯一的解决方案......)

回答后的注意事项

当我收到答案时,我再次阅读了SpriteKit文档并发现了这个清晰的注释:

何时不应使用操作

尽管操作有效,但创建和执行操作会有成本.如果要在每个动画帧中更改节点的属性,并且需要在每个帧中重新计算这些更改,则最好直接对节点进行更改,而不是使用操作来执行此操作.有关在游戏中可能执行此操作的详细信息,请参阅高级场景处理.

Epi*_*yte 7

我有一个炮塔......它应该以手指的位置为目标,但不是立刻,需要时间来转弯.

对于像这样的事情你将无法逃脱SKActions.你可以尝试,但它会非常混乱和低效.您需要对此类物体进行实时运动控制,因为您的炮塔的角速度需要根据触摸位置不断变化.

所以我给你写了一个快速示例项目,展示了如何计算角速度.该项目还处理所有特殊情况,例如防止角度跳过目标旋转.

import SpriteKit

class GameScene: SKScene {
    let turret = SKSpriteNode(imageNamed: "Spaceship")
    let rotationSpeed: CGFloat = CGFloat(M_PI) //Speed turret rotates.
    let rotationOffset: CGFloat = -CGFloat(M_PI/2.0) //Controls which side of the sprite faces the touch point. I offset the angle by -90 degrees so that the top of my image faces the touch point.

    private var touchPosition: CGFloat = 0
    private var targetZRotation: CGFloat = 0

    override func didMoveToView(view: SKView) {
        turret.physicsBody = SKPhysicsBody(rectangleOfSize: turret.size)
        turret.physicsBody!.affectedByGravity = false
        turret.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
        self.addChild(turret)
    }

    override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
        calculateAngleToTouch(touches.anyObject() as UITouch)
    }

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        calculateAngleToTouch(touches.anyObject() as UITouch)
    }

    func calculateAngleToTouch(touch: UITouch) {
        let position = touch.locationInNode(self)
        let angle = atan2(position.y-turret.position.y, position.x-turret.position.x)

        targetZRotation = angle + rotationOffset
    }

    override func update(currentTime: NSTimeInterval) {
        var angularDisplacement = targetZRotation - turret.zRotation
        if angularDisplacement > CGFloat(M_PI) {
            angularDisplacement = (angularDisplacement - CGFloat(M_PI)*2)
        } else if angularDisplacement < -CGFloat(M_PI) {
            angularDisplacement = (angularDisplacement + CGFloat(M_PI)*2)
        }

        if abs(angularDisplacement) > rotationSpeed*(1.0/60.0) {
            let angularVelocity = angularDisplacement < 0 ? -rotationSpeed : rotationSpeed
            turret.physicsBody!.angularVelocity = angularVelocity
        } else {
            turret.physicsBody!.angularVelocity = 0
            turret.zRotation = targetZRotation
        }

    }


}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述