IOS 13 supports gamepad connectivity!! Note that it’s not the gamepads that support iOS 13, but Apple is finally allowing its platforms to “discover” gamepads……

preface

On WWDC19, Apple officially announced that iOS, macOS and tvOS platforms officially support access to controllers that comply with THE MFi protocol for operation. The access mode is “Bluetooth”.

Therefore, we can assume that gamepad support will definitely be considered for all three platforms in the Apple ecosystem in the future. If you look closely at the games currently in the Apple ecosystem, especially on iOS, or mobile, it’s almost impossible to escape a virtual wheel on the left and three or four virtual buttons on the right.

It can be said that these virtual operations are imitating the habits that users have already developed for the original gamepads. These habits are inherited from the physical gamepads era, and Apple did not allow access to other gamepads before iOS 13. So why not go along with the trend now that we have access to other gamepads?

It is also said that some games deliberately detract from the player’s experience through the placement of virtual button positions in order to reduce the speed and quality of completion of certain requirements, which is the modern version of QWERTY.

Choose the right handle

I have already got the Switch, so I naturally added a NS Pro Controller, but fortunately I did some research in advance and found that neither NS Pro Controller nor Joy-Controller supports connection, so I guess Mr. Yan did not apply for MFi certification for his Controller.

So it comes down to PS4 or Xbox controller choice. Before placing the final order, I also did some research and found that everyone generally agreed that the handle of Xbox was much better than that of PS4. I had planned to choose Xbox, but later I found that the advertising on Apple’s official website was PS4, and many up hosts on B website also evaluated based on PS4. Think about the PS4 controller.

So far, I have played for less than three hours, and found that the connection between the gamepad and the device is very stable. Personally, I think there is no delay. However, PS4 gamepad does have netizens saying that the left thumb will hurt after playing for a long time, because I often use half of my thumb to “rub” the slider.

If you’re looking for a playstation 4 controller and you’re not looking for one, you might want to go for the Xbox.

Adaptor handle

Handle difference

Apple’s official documentation recommends that our app/ game should not only support the gamepad, which means that the gamepad is just a tool to enhance the experience, not a necessity, and as long as Apple doesn’t kill us, the game we can experience through the gamepad will be delayed.

PS4 and Xbox gamepads can be understood in two different styles, as shown below:

The ABXY of the PS4 and Xbox gamepads are marked in a different style. But if you’ve ever used either of these controllers, you know that most of them are “positionally equal”, meaning that the X on the PS4 is “positionally equal” to the A on the Xbox, and both are the same functionality for developers.

This point is also retained by Apple, but when we use it, Apple will not tell us whether it is X or A at the current position of A. Apple only has A.

Key conflict

Instead of repeatedly sending key callbacks, Apple automatically helps us retain the final key state for a “fixed amount of time.”

UI

Apple requires a lot in this part. In short, it should either be uniform and make “location equal” identifiers on the UI, or it should return different UI resources according to the identifiers connected to the device.

Access to the

Understand the host handle adaptation of the preceding content, then you can formally enter the handle adaptation part. In the process of adaptation, I was completely overwhelmed by Apple’s simplicity! I expected the calls to the various hardware of the console controller to be as complex as Photos, a very complex framework that doesn’t look like it should be, but is surprisingly simple.

All the work of host handle access only need GameController can be completed, and the framework is platform independent, that is to say, as long as we package a good external exposure of the host handle operation management class, can fully do three platforms all eat!

Step 1: Register notifications

The first step is to register notifications for gamepad connection/disconnection events.

import GameController

class GameController {
    
    init() {
        NotificationCenter.default.addObserver(self, selector: .didConnect, name: .GCControllerDidConnect, object: nil)
        NotificationCenter.default.addObserver(self, selector: .didConnect, name: .GCControllerDidDisconnect, object: nil)}}Copy the code

The second step

Filtering and processing of events is done in the notification callback method.

extension GameController {
    @objc fileprivate func gameControllerDidConnect(a) {
        for controller in GCController.controllers() {
            ifcontroller.extendedGamepad ! =nil {
                setupControllerControls(controller: controller)
            }
        }
    }
    
    @objc fileprivate func gameControllerDidDisconnect(a){}func setupControllerControls(controller: GCController){ controller.extendedGamepad? .valueChangedHandler = { (gamepad:GCExtendedGamepad, element: GCControllerElement) in
            self.controllerInput(gamePad: gamepad, element: element)
        }
    }
    
    private func controllerInput(gamePad: GCExtendedGamepad, element: GCControllerElement){}}Copy the code

The third step

Handles the valueChangedHandler callback event for the handle in controllerInput. ValueChangedHandler this method requires us to pass a callback to the handle control object when we receive a connection notification from the handle, which will be called through our incoming callback when the handle keypress event occurs.

Therefore, in the controllerInput method, we handle changing the values of various events when the handle is pressed.

extension GameController {
    @objc fileprivate func gameControllerDidConnect(a) {
        for controller in GCController.controllers() {
            ifcontroller.extendedGamepad ! =nil {
                setupControllerControls(controller: controller)
            }
        }
    }
    
    @objc fileprivate func gameControllerDidDisconnect(a){}func setupControllerControls(controller: GCController){ controller.extendedGamepad? .valueChangedHandler = { (gamepad:GCExtendedGamepad, element: GCControllerElement) in
            self.controllerInput(gamePad: gamepad, element: element)
        }
    }
    
    private func controllerInput(gamePad: GCExtendedGamepad, element: GCControllerElement) {
        if (gamePad.leftThumbstick == element) {
            if(gamePad.leftThumbstick.yAxis.value ! =0&&! movingY && ! movingX) { movingY =trueisSelectY? (gamePad.leftThumbstick.yAxis.value >0)
                return
            } else if (gamePad.leftThumbstick.yAxis.value == 0) {
                movingY = false
            }
            
            if(gamePad.leftThumbstick.xAxis.value ! =0&&! movingX && ! movingY) { isSelectX? (gamePad.leftThumbstick.xAxis.value >0)
                movingX = true
                return
            } else if (gamePad.leftThumbstick.xAxis.value == 0) {
                movingX = false}}if (gamePad.buttonA == element) {
            if(gamePad.buttonA.value ! =0) { isTapButtonA? ()}}// ...
}
Copy the code

ValueChangedHandler callback is just a callback when the value changes, we also need to manually handle for example the single count from hold to return on the joystick, of course, I’m doing this for my game, this part hasn’t been improved yet, if you want to continuously listen for the joystick hold event, It can be exposed to the outside world, and it can be multiplied by coefficients to do fun things like control the throttle of a racing car.

Externally, single keystroke events can be passed through registered callbacks.

class GameController {
    
    var movingX = false
    var movingY = false
    
    var isSelectX: ((Bool) - > ())?var isSelectY: ((Bool) - > ())?var isTapButtonA: (() -> ())?

    / /...
}

// ...
Copy the code

conclusion

I didn’t expect the first gamepad adaptation to take less than 80 lines of code. The controller is a player’s weapon as well as a symbol, and I hope everyone will consider supporting the controller in their own games to provide a better gaming experience.

If you’re interested in my first gamepad game, “Can I Turn off the lights”, you can find this project on Github, and if you want to work with me on developing games via Swift, you can find Swift Game Development on the small column.

Github address: Swift Game Development

Small column address: Swift game development

Refer to the link

  • Developer.apple.com/videos/play…
  • medium.com/@samdubois1…