Skip to content

Instantly share code, notes, and snippets.

@perezpaya
Last active April 23, 2016 21:30
Show Gist options
  • Save perezpaya/e85fe2a987cf56a72ad528ad737608f3 to your computer and use it in GitHub Desktop.
Save perezpaya/e85fe2a987cf56a72ad528ad737608f3 to your computer and use it in GitHub Desktop.
import SpriteKit
class Joystick: SKNode {
private let substrate: SKSpriteNode
private let stick: SKSpriteNode
var resetAnimationDuration: NSTimeInterval = 0.3
var velocity: CGPoint = .zero
var angularVelocity: CGFloat = 0
override var zPosition: CGFloat {
get {
return super.zPosition
}
set {
super.zPosition = newValue
recalculateNodesZPosition()
}
}
private var anchorPoint: CGPoint {
return CGPointMake(0, 0)
}
var expectedSize: CGSize {
return CGSizeMake(substrate.size.width + substrate.size.width, substrate.size.height + substrate.size.height)
}
override init(substrateSprite: SKSpriteNode, stickSprite: SKSpriteNode) {
substrate = substrateSprite
stick = stickSprite
super.init()
setup()
}
private func setup() {
userInteractionEnabled = true
setupSubtrate()
setupStick(substrate.position)
recalculateNodesZPosition()
}
private func setupSubtrate() {
substrate.xScale = 0.3
substrate.yScale = 0.3
substrate.zPosition = self.zPosition
addChild(substrate)
}
private func setupStick(position: CGPoint) {
stick.xScale = 0.22
stick.yScale = 0.22
stick.zPosition = substrate.zPosition + 1
moveStick(position)
addChild(stick)
}
private func recalculateNodesZPosition() {
substrate.zPosition = zPosition
stick.zPosition = substrate.zPosition + 1
}
private func moveStick(position: CGPoint) {
stick.position = position
}
private func resetStick() {
let animation = SKAction.moveTo(anchorPoint, duration: resetAnimationDuration)
animation.timingMode = SKActionTimingMode.EaseOut
stick.runAction(animation)
}
private func resetVelocity() {
velocity = .zero
angularVelocity = 0
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first where substrate == nodeAtPoint(touch.locationInNode(self)) {
let position = touch.locationInNode(self)
moveStick(position)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
touches.forEach { t in
let location = t.locationInNode(self)
if sqrtf(powf((Float(location.x) - Float(stick.position.x)), 2) + powf((Float(location.y) - Float(stick.position.y)), 2)) < Float(stick.size.width) {
moveStick(calculateStickPosition(forTouchPoint: location))
}
self.velocity = CGPointMake(((stick.position.x - anchorPoint.x)), ((stick.position.y - anchorPoint.y)))
self.angularVelocity = -atan2(stick.position.x - anchorPoint.x, stick.position.y - anchorPoint.y)
}
}
private func calculateStickPosition(forTouchPoint touchPoint: CGPoint) -> CGPoint {
if sqrtf(powf((Float(touchPoint.x) - Float(anchorPoint.x)), 2) + powf((Float(touchPoint.y) - Float(anchorPoint.y)), 2)) <= Float(stick.size.width) {
let moveDifference: CGPoint = CGPointMake(touchPoint.x - anchorPoint.x, touchPoint.y - anchorPoint.y)
return CGPointMake(anchorPoint.x + moveDifference.x, anchorPoint.y + moveDifference.y)
} else {
let vX: Double = Double(touchPoint.x) - Double(anchorPoint.x)
let vY: Double = Double(touchPoint.y) - Double(anchorPoint.y)
let magV: Double = sqrt(vX*vX + vY*vY)
let aX: Double = Double(anchorPoint.x) + vX / magV * Double(stick.size.width)
let aY: Double = Double(anchorPoint.y) + vY / magV * Double(stick.size.width)
return CGPointMake(CGFloat(aX), CGFloat(aY))
}
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
resetVelocity()
resetStick()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
resetVelocity()
resetStick()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment