The Virtual Game Controller can run on any view controller running iOS 15 At least but for the purpose of work it is best viewed in landscape but you need to complete the codes as a physical gamepad.
For the virtual game controller to appear you need to register a physical game controller and apply the functions of notification when connect and disconnect a controller as you do with physical controller exactly.
Here is a code to setup and register a virtual and physical game controller I use and it works for me.
1st you need to import the Game Controller Library
import GameController
Then you define the Virtual Controller Under your Controller Class
class GameViewController: UIViewController {
// Virtual Onscreen Controller
private var _virtualController: Any?
@available(iOS 15.0, *)
public var virtualController: GCVirtualController? {
get { return self._virtualController as? GCVirtualController }
set { self._virtualController = newValue }
}
And then you call the setupGameController Function In Your ViewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
//your code
setupGameController()
}
and here is the main function to setup your Virtual and physical game controller
func setupGameController() {
NotificationCenter.default.addObserver(
self, selector: #selector(self.handleControllerDidConnect),
name: NSNotification.Name.GCControllerDidBecomeCurrent, object: nil)
NotificationCenter.default.addObserver(
self, selector: #selector(self.handleControllerDidDisconnect),
name: NSNotification.Name.GCControllerDidStopBeingCurrent, object: nil)
if #available(iOS 15.0, *)
{
let virtualConfiguration = GCVirtualController.Configuration()
virtualConfiguration.elements = [GCInputLeftThumbstick,
GCInputRightThumbstick,
GCInputButtonA,
GCInputButtonB]
virtualController = GCVirtualController(configuration: virtualConfiguration)
// Connect to the virtual controller if no physical controllers are available.
if GCController.controllers().isEmpty {
virtualController?.connect()
}
}
guard let controller = GCController.controllers().first else {
return
}
registerGameController(controller)
}
Then to act with the virtual or physical gamepad actions you need to assign the connect and register for the game controller
as
func handleControllerDidConnect(_ notification: Notification) {
guard let gameController = notification.object as? GCController else
{
return
}
unregisterGameController()
if #available(iOS 15.0, *)
{
if gameController != virtualController?.controller
{
virtualController?.disconnect()
}
}
registerGameController(gameController)
}
func handleControllerDidDisconnect(_ notification: Notification) {
unregisterGameController()
if #available(iOS 15.0, *) {
if GCController.controllers().isEmpty
{
virtualController?.connect()
}
}
}
func registerGameController(_ gameController: GCController) {
var buttonA: GCControllerButtonInput?
var buttonB: GCControllerButtonInput?
if let gamepad = gameController.extendedGamepad
{
buttonA = gamepad.buttonA
buttonB = gamepad.buttonB
}
buttonA?.valueChangedHandler = {(_ button: GCControllerButtonInput, _ value: Float, _ pressed: Bool) -> Void in
// Put here the codes to run when button A clicked
print("Button A Pressed")
}
buttonB?.valueChangedHandler = {(_ button: GCControllerButtonInput, _ value: Float, _ pressed: Bool) -> Void in
// Put here the codes to run when button B clicked
print("Button B Pressed")
}
}
func unregisterGameController()
{
}
And Here Is A Result of the code on a very basic ship sample of Xcode
