2021 DesignEssentialsGraphics & Games
WWDC21 · 15 min · Design / Essentials / Graphics & Games
Tap into virtual and physical game controllers
It’s time to up your input game: Learn about the latest improvements to virtual and physical game controllers for iPhone, iPad, Mac, and Apple TV. Meet the virtual on-screen controller, which turns touch input into game controller input, and find out how to add controller sharing features to your app. We’ll also show you how to support adaptive trigger technology found in DualSense controllers, provide best practices for controller support, and take you through some common pre-flight checks around accessible and customizable input before submitting to the App Store. For more information on saving highlight clips from a game controller, check out “Discover rolling clips in ReplayKit” from WWDC21.
Watch at developer.apple.com ↗Code shown on screen · 4 snippets
GameController Basics
func setupGameController() {
// Add handler for when controller connects.
NotificationCenter.default.addObserver(
forName: NSNotification.Name.GCControllerDidConnect,
object: nil,
queue: nil)
{ (note) in
guard let _controller = note.object? as GCController else {
return
}
// Add controller input change handlers.
_controller.physicalInputProfile[GCInputButtonA]?.valueChangedHandler = { ... }
_controller.physicalInputProfile[GCInputButtonB]?.valueChangedHandler = { ... }
}
// Add handler for when controller disconnects.
NotificationCenter.default.addObserver(
forName: NSNotification.Name.GCControllerDidDisconnect,
object: nil,
queue: nil)
{ (note) in ... }
}
// Polling for controller input.
func checkInput() {
if controller.physicalInputProfile[GCInputButtonA]?.pressed { ... }
if controller.physicalInputProfile[GCInputButtonB]?.pressed { ... }
} Virtual Controller Initial
// Creating an on-screen controller
let virtualConfiguration = GCVirtualControllerConfiguration()
virtualConfiguration.elements = [GCInputLeftThumbstick,
GCInputRightThumbstick,
GCInputButtonA,
GCInputButtonB]
let virtualController = GCVirtualController(configuration: virtualConfiguration)
virtualController.connect() Customizing Buttons
// Creating customized buttons
vc.changeElement(GCInputButtonA) {
config in
let spinningPath = UIBezierPath()
// load or draw the spinning attack path
config.path = spinningPath
return config
}
vc.changeElement(GCInputButtonB) {
config in
let jumpPath = UIBezierPath()
// load or draw the jump path
config.path = jumpPath
return config
} DualSense Adaptive Triggers
func updateControllerAdaptiveTriggers() {
guard let dualSense = GCController.current?.physicalInputProfile as? GCDualSenseGamepad
else {
return
}
let adaptiveTrigger = dualSense.rightTrigger
if playerIsPullingSlingshot {
let resistiveStrength = min(1, 0.4 + adaptiveTrigger.value)
if adaptiveTrigger.value < 0.9 {
adaptiveTrigger.setModeFeedbackWithStartPosition(
0,
resistiveStrength: resistiveStrength)
} else {
adaptiveTrigger.setModeVibrationWithStartPosition(
0,
amplitude: resistiveStrength,
frequency: 0.03)
}
} else if adaptiveTrigger.mode != .off {
adaptiveTrigger.setModeOff()
}
} Resources
Related sessions
-
15 min -
27 min -
9 min -
25 min -
14 min