Swift/iOS/PadOverlay.swift
/* |
Copyright (C) 2018 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Exposes D-Pad game controller type functionality with screen-rendered buttons. |
*/ |
import SpriteKit |
import simd |
protocol PadOverlayDelegate: NSObjectProtocol { |
func padOverlayVirtualStickInteractionDidStart(_ padNode: PadOverlay) |
func padOverlayVirtualStickInteractionDidChange(_ padNode: PadOverlay) |
func padOverlayVirtualStickInteractionDidEnd(_ padNode: PadOverlay) |
} |
class PadOverlay: SKNode { |
// Default 100, 100 |
var size = CGSize.zero { |
didSet { |
if size != oldValue { |
updateForSizeChange() |
} |
} |
} |
// Range [-1, 1] |
var stickPosition = CGPoint.zero { |
didSet { |
if stickPosition != oldValue { |
updateStickPosition() |
} |
} |
} |
weak var delegate: PadOverlayDelegate? |
private var trackingTouch: UITouch? |
private var startLocation = CGPoint.zero |
private var stick: SKShapeNode! |
private var background: SKShapeNode! |
override init() { |
super.init() |
size = CGSize(width: CGFloat(150), height: CGFloat(150)) |
alpha = 0.7 |
isUserInteractionEnabled = true |
buildPad() |
} |
required init?(coder aDecoder: NSCoder) { |
fatalError("init(coder:) has not been implemented") |
} |
func buildPad() { |
let backgroundRect = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(size.width), height: CGFloat(size.height)) |
background = SKShapeNode() |
background.path = CGPath( ellipseIn: backgroundRect, transform: nil ) |
background.strokeColor = SKColor.black |
background.lineWidth = 3.0 |
addChild(background) |
var stickRect = CGRect.zero |
stickRect.size = stickSize |
stick = SKShapeNode() |
stick.path = CGPath( ellipseIn: stickRect, transform: nil) |
stick.lineWidth = 2.0 |
//#if os( OSX ) |
stick.fillColor = SKColor.white |
//#endif |
stick.strokeColor = SKColor.black |
addChild(stick) |
updateStickPosition() |
} |
var stickSize: CGSize { |
return CGSize( width: size.width / 3.0, height: size.height / 3.0) |
} |
func updateForSizeChange() { |
guard let background = background else { return } |
let backgroundRect = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(size.width), height: CGFloat(size.height)) |
background.path = CGPath( ellipseIn: backgroundRect, transform: nil) |
let stickRect = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(size.width / 3.0), height: CGFloat(size.height / 3.0)) |
stick.path = CGPath( ellipseIn: stickRect, transform: nil) |
} |
func updateStickPosition() { |
let stickSize: CGSize = self.stickSize |
let stickX = size.width / 2.0 - stickSize.width / 2.0 + size.width / 2.0 * stickPosition.x |
let stickY = size.height / 2.0 - stickSize.height / 2.0 + size.width / 2.0 * stickPosition.y |
stick.position = CGPoint(x: stickX, y: stickY) |
} |
func updateStickPosition(forTouchLocation location: CGPoint) { |
var l_vec = vector_float2( x: Float( location.x - startLocation.x ), y: Float( location.y - startLocation.y ) ) |
l_vec.x = (l_vec.x / Float( size.width ) - 0.5) * 2.0 |
l_vec.y = (l_vec.y / Float( size.height ) - 0.5) * 2.0 |
if simd_length_squared(l_vec) > 1 { |
l_vec = simd_normalize(l_vec) |
} |
stickPosition = CGPoint( x: CGFloat( l_vec.x ), y: CGFloat( l_vec.y ) ) |
} |
func resetInteraction() { |
stickPosition = CGPoint.zero |
trackingTouch = nil |
startLocation = CGPoint.zero |
delegate!.padOverlayVirtualStickInteractionDidEnd(self) |
} |
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { |
trackingTouch = touches.first |
startLocation = trackingTouch!.location(in: self) |
// Center start location |
startLocation.x -= size.width / 2.0 |
startLocation.y -= size.height / 2.0 |
updateStickPosition(forTouchLocation: trackingTouch!.location(in: self)) |
delegate!.padOverlayVirtualStickInteractionDidStart(self) |
} |
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { |
if touches.contains(trackingTouch!) { |
updateStickPosition(forTouchLocation: trackingTouch!.location(in: self)) |
delegate!.padOverlayVirtualStickInteractionDidChange(self) |
} |
} |
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { |
if touches.contains(trackingTouch!) { |
resetInteraction() |
} |
} |
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { |
if touches.contains(trackingTouch!) { |
resetInteraction() |
} |
} |
} |
Copyright © 2018 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2018-04-05