Rotate sprite by touch with a limited rotation speed
I have a turret which ... should target the finger position, but not immediately, by taking time to turn.
You won't be able to get away with SKActions for something like this. You can try but it will be really messy and inefficient. You need real-time motion control for something like this because the angular velocity of your turret needs to change constantly depending on the touch position.
So I wrote you a quick example project showing how to calculate the angular velocity. The project handles all special cases as well, such as preventing the angle from jumping over your target rotation.
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
}
}
}