Move Sprite Based Off of Degrees - swift

I've been able to detect degrees, but I'm unsure on how to move the sprite in 360 degrees.
I don't want the sprite to be able to only move in certain sections, as shown in the picture above, but rather have it be able to move in a full circle.
Code:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if (ball.frame.contains(location)) {
stickActive = true
}else {
stickActive = false
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if (stickActive == true) {
var v = CGVector(dx: location.x - base.position.x, dy: location.y - base.position.y)
let angle = atan2(v.dy, v.dx)
var deg = angle * CGFloat(180 / M_PI)
print(deg + 180)
let lenght:CGFloat = base.frame.size.height / 2 - 20
let xDist: CGFloat = sin(angle - 1.57079633) * lenght
let yDist: CGFloat = cos(angle - 1.57079633) * lenght
ball.position = CGPoint(x: base.position.x - xDist, y: base.position.y + yDist)
if (base.frame.contains(location)) {
ball.position = location
}else {
ball.position = CGPoint(x: base.position.x - xDist, y: base.position.y + yDist)
}
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if (stickActive == true) {
let move: SKAction = SKAction.move(to: base.position, duration: 0.2)
move.timingMode = .easeOut
ball.run(move)
}
}

This is super simple, although it took me quite awhile to figure out how to do it.
TouchesBegan method:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if isTracking == false && DPad.contains(location) {
isTracking = true
}
}
}
TouchesMoved method:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location: CGPoint = touch.location(in: self)
if isTracking == true {
v = CGVector(dx: location.x - DPad.position.x, dy: location.y - DPad.position.y)
let angle = atan2(v.dy, v.dx)
let deg = angle * CGFloat(180 / Double.pi)
let Length:CGFloat = DPad.frame.size.height / 2
let xDist: CGFloat = sin(angle - 1.57079633) * Length
let yDist: CGFloat = cos(angle - 1.57079633) * Length
xJoystickDelta = location.x - DPad.position.x
yJoystickDelta = location.y - DPad.position.y
if DPad.contains(location) {
thumbNode.position = location
} else {
thumbNode.position = CGPoint(x: DPad.position.x - xDist, y: DPad.position.y + yDist)
}
}
}
}
TouchesEnded method:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
isTracking = false
thumbNode.run(SKAction.move(to: DPad.position, duration: 0.01))
xJoystickDelta = 0
yJoystickDelta = 0
}
The update(_ currentTime:) method:
if v.dx > abs(v.dy) {
yourPlayer.texture = SKTexture(imageNamed: "rightTexture")
} else if v.dx < -abs(v.dy) {
player.texture = SKTexture(imageNamed: "leftTexture")
} else if v.dy < 0 {
yourPlayer.texture = SKTexture(imageNamed: "frontTexture")
} else if v.dy > 0 {
yourPlayer.texture = SKTexture(imageNamed: "backTexture")
}
//This code moves your character where-ever you want it too
let xScale = CGFloat(4) //adjust to your preference. Higher means slower, lower means faster
let yScale = CGFloat(4) //adjust to your preference. Higher means slower, lower means faster
let xAdd = xScale * self.xJoystickDelta
let yAdd = yScale * self.yJoystickDelta
yourPlayerNode.position.x += xAdd
yourPlayerNode.position.y += yAdd
These things need to be outside your didMove(toView:) method:
var xJoystickDelta:CGFloat = 0
var yJoystickDelta:CGFloat = 0
var v = CGVector()
var isTracking:Bool = false
var DPad = SKSpriteNode()
var thumbNode = SKSpriteNode()
-Explanation-
In the touchesBegan method, the if-statement is testing to see if you are not controlling the thumbNode and if your touch is inside the DPad Node. Then it starts the tracking.
In the touchesMoved once isTracking == true it starts calculating the neccessary math and then adjusting the various things required. (its complicated, what matters most is that it works.)
In the touchesEnded method, it is testing to see when you lift your finger off of the screen, then it resets everything for the next usage.
In the update(_ current:) method, the code is calculating the angle of the CGVector and then setting a texture (or whatever you want to do) inside of the various cases. Then its calculating the position of the thumbNode inside the DPad and moving your player (or whatever you need to move) around in the scene. Adjust the xScale and yScale floats higher to slow down the movement, and lower to increase the movement of whatever you are trying to move.
-Extra neccessary stuff-
You need to set up the DPad and thumbNode inside your didMove(toView:) method:
thumbNode.size = CGSize(width: 50, height: 50)
DPad.size = CGSize(width: 150, height: 150)
DPad.position = CGPoint(x: 0, y: 0)
thumbNode.position = DPad.position
DPad.zPosition = 3
thumbNode.zPosition = 4
DPad.texture = SKTexture(imageNamed: "yourBaseTexture")
thumbNode.texture = SKTexture(imageNamed: "yourStickTexture")
self.addChild(thumbNode)
self.addChild(DPad)
You only have to move the DPad.position to wherever you want. The thumbNode will move along with it. Also, if you have any problems be sure to ask me so I can help you.

Related

Sprite follows finger when dragged on screen Spritekit

I am attempting to create a walking animation where the sprite moves towards a touch location that can be dragged around the screen. I have managed to get Xcode to print updated X and Y coordinates where the finger is dragged but the sprite will barely move and I haven't been able to solve this issue. The touchesMoved has correctly printed the x and y coordinates but the moveGuy function will not perform correctly.
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches { self.touchMoved(toPoint: touch.location(in: self))
let location = touch.location(in: self)
print(location)
moveGuy(location: location)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guyMoveEnded()
}
func moveGuy(location: CGPoint) {
var multiplierForDirection: CGFloat
// 2
let guySpeed = frame.size.width / 3.0
// 3
let moveDifference = CGPoint(x: location.x - guy.position.x, y: location.y - guy.position.y)
let distanceToMove = sqrt(moveDifference.x * moveDifference.x + moveDifference.y * moveDifference.y)
// 4
let moveDuration = distanceToMove / guySpeed
// 5
if moveDifference.x < 0 {
multiplierForDirection = -1.0
} else {
multiplierForDirection = 1.0
}
guy.xScale = abs(guy.xScale) * multiplierForDirection
// 1
if guy.action(forKey: "walkingInPlaceguy") == nil {
// if legs are not moving, start them
animateguy()
}
if guy.position == (location) {
guyMoveEnded()
}
// 2
let moveAction = SKAction.move(to: location, duration:(TimeInterval(moveDuration)))
// 3
let doneAction = SKAction.run({ [weak self] in
self?.guyMoveEnded()
})
// 4
let moveActionWithDone = SKAction.sequence([moveAction, doneAction])
guy.run(moveActionWithDone, withKey:"guyMoving")
}

can't rotate a circle node around a fix point

I'm trying to set a SKShapeNode that rotating around fixed point depend on user's swipe gesture. to do so i'm using the code that answered here.
when I set the node as a rectangle - it's working just fine, the problem is when I trying to set the node as a circle (as I needed it to be). I have no idea why its happening, and what makes the difference.
here is the code that works (SKShapeNode as a rectangle):
override func didMove(to view: SKView) {
let ball = SKShapeNode(rect: CGRect(x: 100, y: 100, width: 100, height: 100))
ball.fillColor = SKColor.red
ball.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
ball.name = "BALL"
ball.physicsBody = SKPhysicsBody(circleOfRadius: 200)
ball.physicsBody?.angularDamping = 0.25
ball.physicsBody?.pinned = true
ball.physicsBody?.affectedByGravity = false
self.addChild(ball)
let om = 5.0
let er = 4.0
let omer = atan2(om, er)
print("om = \(om), er = \(er), atan2(omer) = \(omer)")
}
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 == "BALL" {
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 == "BALL" {
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
}
but when i change the SKShapeNode (inside my didMove function) to circle is just dont work - here is the changed code:
override func didMove(to view: SKView) {
let ball = SKShapeNode(circleOfRadius: 200)
ball.fillColor = SKColor.red
ball.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
ball.name = "BALL"
ball.physicsBody = SKPhysicsBody(circleOfRadius: 200)
ball.physicsBody?.angularDamping = 0.25
ball.physicsBody?.pinned = true
ball.physicsBody?.affectedByGravity = false
self.addChild(ball)
}
does anyone see/ know what am I dong wrong?
How would you expect to see that the shape is turning? Do you have something inside the shapenode with a texture that you can actually see rotating?
A turning circle shapenode looks the same as a static one. In the update loop of the scene grab the ball and print its zRotation to see if it's actually turning.
override func update(_ currentTime: TimeInterval) {
var ball: SKShapeNode = childNodeWithName("BALL") as SKShapeNode
print(ball.zRotation)
}
(this code was written without access to Swift so you might have to fix the syntax a tiny bit)
Remember the zRotation is measured in radians so it might not look how you expect but it it's changing then the SKShapeNode is actually rotating, you just can't see it.
You'll have to add a child node that has something visible on it.

how do i make a node go from one side of the screen to the other?

I'm just starting in sprite kit and have hit a road block. I'm trying to recreate the old atari game asteroids. I'm currently trying to find out how to move the node "ship" from one side of the screen and come out the opposite side. An example of this would be pacman going from the right side of the screen and out the left side of the screen. Help is greatly appreciated.
Thanks in advance,
Jared
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate{
let base = SKSpriteNode(imageNamed: "Base")
let ball = SKSpriteNode(imageNamed: "Ball")
let ship = SKSpriteNode(imageNamed: "Ship")
let shoot = SKSpriteNode(imageNamed: "shootButton")
override func didMoveToView(view: SKView){
// var DynamicView=UIView(frame: CGRectMake(100, 200, 100, 100))
// DynamicView.backgroundColor=UIColor.greenColor()
// DynamicView.layer.cornerRadius=2
// DynamicView.layer.borderWidth=2
// self.view!.addSubview(DynamicView)
self.anchorPoint = CGPointMake(0.5, 0.5)
self.physicsWorld.contactDelegate = self
self.physicsWorld.gravity = CGVectorMake(0.0, 0.0)
self.addChild(base)
base.position = CGPointMake(-350, -200)
self.addChild(shoot)
shoot.position = CGPointMake(350, -200)
self.addChild(ball)
ball.position = base.position
self.addChild(ship)
ship.position = CGPointMake(20, 47)
ship.xScale = 0.7
ship.yScale = 0.7
ship.physicsBody?.dynamic = true
ship.physicsBody?.allowsRotation = true
ship.physicsBody?.affectedByGravity = true
ship.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Ship"), size: ship.size)
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
ball.alpha = 0.4
base.alpha = 0.4
}
// func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
// /* Called when a touch begins */
//
// for touch in (touches as! Set<UITouch>) {
// let location = touch.locationInNode(self)
//
//
// }
// }
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
let v = CGVector(dx: location.x - base.position.x, dy: location.y - base.position.y)
let angle = atan2(v.dy, v.dx)
let deg = angle * CGFloat(180 / M_PI)
// print( deg + 180)
let length:CGFloat = base.frame.size.height / 2
let xDist:CGFloat = sin(angle - 1.57079633) * length
let yDist:CGFloat = cos(angle - 1.57079633) * length
ball.position = CGPointMake(base.position.x - xDist, base.position.y + yDist)
if CGRectContainsPoint(base.frame, location) {
ball.position = location
}
else{
ball.position = CGPointMake(base.position.x - xDist, base.position.y + yDist)
}
ship.zRotation = angle - 1.57079633
ship.physicsBody?.mass = 2
var shipRotation : CGFloat = ship.zRotation
var calcRotation : Float = Float(angle - 1.57079633) + Float(M_PI_2);
let intensity : CGFloat = 2000.0 // put your value
let xVelocity = intensity * CGFloat(cosf(calcRotation))
let yVelocity = intensity * CGFloat(sinf(calcRotation))
let vector : CGVector = CGVectorMake(xVelocity, yVelocity)
//Apply force to spaceship
ship.physicsBody?.applyForce(vector)
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
let move:SKAction = SKAction.moveTo(base.position, duration: 0.2)
move.timingMode = .EaseOut
ball.runAction(move)
}
}
// overridefunc update(currentTime: CFTimeInterval) {
// /* Called before each frame is rendered */
//
//}
In func update(currentTime) check if ship.position.x < 0 or ship.position.x > scene.width. If true, set ship.position.x to the opposite side.
It looks like you're using physics to move the ship (as opposed to updating its position by a certain amount in the update() method)
So what you could do is to override the didiSimulatePhysics() method (which is called after the SpriteKit game engine has done all the physics calculations and moved all the nodes) and if your ship is off screen (which you could do by seeing if it's position is outside the screne's x & y boundaries, or by using the intersectsRect method to see if. The ship's frame no longer overlaps the screen frame) and if it is, simply wrap it to the other side of the screen.

Continous minimum velocity tracking of a finger on a sprite in spritekit/ios

What is a good way to continuously track the velocity of a user moving their finger up and down on a sprite without lifting the finger? And if they don't go fast enough(set a minimum) to perform an action.
This is some code you can use to drag a sprite across the screen at different speeds depending on your finger acceleration. You can add your own code to detect the magnitude of change and perform whichever action you want..
class GameScene: SKScene {
// time values
var delta:NSTimeInterval = NSTimeInterval(0)
var last_update_time:NSTimeInterval = NSTimeInterval(0)
// our sprite
let sprite = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 20, height: 30))
// tracking difference between touches
var currentTouchY: CGFloat = CGFloat(0)
var lastTouchY: CGFloat = CGFloat(0)
// the magnitude of change between current and last touch
var forceMag: CGFloat = CGFloat(0)
// max mag so our sprite doesnt travel at crazy speed
let forceMagMax: CGFloat = CGFloat(7)
// direction of our sprites travel
var forceDir: CGFloat = CGFloat(0)
// arbitrary speed we want sprite to move
let velocity: CGFloat = CGFloat(70)
// we use this to stop moving our sprite when we let go
var intervalsWithoutChange = 0
override func didMoveToView(view: SKView) {
sprite.position.x = 100
sprite.position.y = size.width/2
self.addChild(sprite)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let yCoord = location.y
lastTouchY = yCoord
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let yCoord = location.y
intervalsWithoutChange = 0
currentTouchY = yCoord
let diff = currentTouchY - lastTouchY
forceMag = abs(diff)
forceMag = forceMag > forceMagMax ? forceMagMax : forceMag
forceDir = diff < 0 ? -1 : 1
lastTouchY = yCoord
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
intervalsWithoutChange = 1
currentTouchY = 0
lastTouchY = 0
}
override func update(currentTime: NSTimeInterval) {
if last_update_time == 0.0 {
delta = 0
} else {
delta = currentTime - last_update_time
}
last_update_time = currentTime
if intervalsWithoutChange > 0 {
forceMag -= CGFloat(15) * CGFloat(delta)
}
if forceMag < 0.01 {
forceMag = 0
}
let change = forceDir * pow(forceMag, 1.29)
sprite.position.y += change * CGFloat(delta) * velocity
}
}

Drag Rotate a Node around a fixed point

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.
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.
Here's my code.
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.
I can add the PanGestureRecognizer code if needed but I'll try to keep it short for now.
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
}
}
}
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
}
}
The zRotation of a SKNode is in radians. You can remove your conversion to degrees.
You may wish to do the angle adjustment in the didSimulatePhysics in order to compute the zRotation after physics have been applied. (This may not apply directly to this situation, but is good practice further down the line.)
I tried two set of coodes below.
Code Sample 1
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let node = atPoint(location)
guard let safeNode = node.parent else { break }
if safeNode.name == "wheel" {
let wheel = node.parent!
let dx = location.x
let dy = location.y
startingAngle = atan2(dx, dy)
startingTime = touch.timestamp
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let node = atPoint(location)
guard let safeNode = node.parent else { break }
if safeNode.name == "wheel" {
let wheel = node.parent!
if !isRotating {
let dx = location.x
let dy = location.y
let angle = atan2(dx, dy)
wheel.zRotation = -angle
//update angle and time
startingAngle = angle
startingTime = touch.timestamp
}
}
}
}
Code Sample 2
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let node = atPoint(location)
guard let safeNode = node.parent else { break }
if safeNode.name == "wheel" {
let wheel = node.parent!
let dx = location.x
let dy = location.y
startingAngle = atan2(dx, dy)
startingTime = touch.timestamp
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let node = atPoint(location)
guard let safeNode = node.parent else { break }
if safeNode.name == "wheel" {
let wheel = node.parent!
if !isRotating {
let dx = location.x
let dy = location.y
let angle = atan2(dx, dy)
let deltaAngle = angle - startingAngle!
wheel.zRotation -= deltaAngle
//update angle and time
startingAngle = angle
startingTime = touch.timestamp
}
}
}
}
The only difference between Code Sample 1 & 2 is the method of finding zRotation of the wheel.
Code Sample 1 uses wheel.zRotation = -angle. It ensures wheel follows the finger position exactly. But there is a bug that the wheel will jump position when you touch two distant locations in wheel then move your fingure. I am still unable to fix this bug.
Code Sample 2 uses wheel.zRotation -= deltaAngle to stack the change in angle of each finger movement. It supposes to generate the same result of code sample 1 but it does not exactly follow the finger movement.
I found out the reason by comparing the zPosition of Code Sample 1 and 2 with same finger movement. The deltaAngle in Code Sample 2 is slightly less (up to 8 decimal places)so the wheel does not exactly follow the fingure movement.