The Game Controller framework enables games to integrate with MFi game controllers and take advantage of exciting new modes of input. Check out the latest additions and get expert advice about best practices to follow when adding game controller support to your titles. Understand how to avoid common pitfalls and gain key insights into what it takes to create an experience that's intuitive and fun.
Thank you. Good morning, good morning. And welcome.
You know, I love games.
I've been playing them my whole life. I love making games.
I love teaching about games.
And I'm really excited to talk to you today about designing for game controllers.
My name is JJ Cwik, and I'm a software engineer on the Game Play Technology Team or on the Game Technology Team at Apple. Now, let me poll the audience.
How many of you have already integrated game controllers into a game before? All right, a few. Great. And for how many of you will this be your first talk on game controllers? Good. Large majority. Great. Wonderful. So, this is going to be fun. Let's get started.
When I talk about game controllers, what Apple is delivering is in two parts.
The first part is the MFi Specification.
Now, this is for third-party controller developers.
It defines all the hardware requirements of the controllers.
Things like: the control layouts on the gamepad itself; how the buttons feel when you press them; and the communication protocols between the device.
And the goal with this program is to give confidence to consumers that when they purchase a game controller that has one of these icons on the box, they're assured that their game controller is going to work with all your games that support the game controller framework.
So that's the first part, the MFi Specification.
The second part is the game controller framework.
This is the software side of things, what you as game developers will be using to integrate game controllers into your games.
This is an iOS and OS X cross-platform framework.
So code that you write for game controllers in one is directly usable in the other. And it features a simple API, which allows you to find controllers and read the input off of those controllers.
And the goal with this side of things with the framework is to give you one API so that you can focus on developing your game, integrating game controllers really smoothly and not have to worry about little variations in all sorts of different controllers.
So that's the second part, the game controller framework.
Now, what kind of controllers are available? There are three types.
The first type is a form-fitting standard controller.
And by form-fitting, we mean that the controller encases the device.
Therefore, the touch screen is easily accessible while they're playing with the game pad, and so is motion control of the device.
And by "standard," we're referring to the controls layout on the gamepad, specifically that there's a D-pad, that there are four face buttons (A, B, X and Y, always in these colors and in these locations) and two shoulder buttons (L and R).
So that's the first controller type.
The second controller is the form-fitting extended controller.
So it too is form-fitting.
And the extended control layout has all the same controls of the standard controller, but it adds to it two thumbsticks and two triggers.
That's the second controller type.
The third controller type is the standalone extended controller.
And by standalone, we mean the controller does not encase the device.
So the touch screen is not easily accessible. Motion control is not an option.
You're only getting input from the controller itself.
And again, this has the exact same extended control layout as the previous extended controller.
So that's an overview.
Now, I'm going to focus the rest of my talk on the game controller framework itself and how you use the framework to integrate game controllers into your games.
Specifically, we're going to find out inside your game, how do you know which controllers are available for your game to use? We're going to talk about finding controllers.
I'm also going to talk about the various inputs found on controllers, like the buttons and the D-pads and how those map in software, and how you can read whether or not a player is pressing the A button or the D-pad.
I'm also going to talk about what's new.
What have we been working on this past year? What are we introducing at iOS 8 and with respect to game controllers? One really cool thing that I'm excited to tell you about is controller forwarding.
In a nutshell, this is a way for a controller with a snapped-in iPhone to be used as a wireless controller to control the game play experience on another device, like an iPad. And throughout the talk, I'm going to be giving a heavy emphasis to design guidance.
It's actually fairly straightforward to integrate game controllers into your game.
And it's going to be really instructive to talk about design guidance based on things that we've seen this past year.
And I'd really like to focus especially on an Apple Design Award winning game this year, Leo's Fortune, because it integrates game controllers really, really well. It's a fantastic integration. And I think it's going to be really instructive for all of us. So, let's talk about finding controllers. How do I know which controllers are available to my game? The first thing you're going to want know is the main class that you're going to be interacting with in the game controller framework is called GCController. Now, this is the same class for all controller types.
And it allows you to do a few things, like finding which controllers are available, reading the inputs off of the controllers and additional information about the controller itself, such as whether or not it's form-fitting, if it's standard or extended.
Now, to find which controllers are currently connected, call the controllers class method on GCController.
It returns you an array of currently connected controllers.
Or, an empty array if no controllers are connected.
Now, this array starts off empty.
And it's updated as controllers are added and removed from the system.
So whenever you check this method, it'll return you the latest information on what's currently connected. Now let me explain visually how we're going to structure our code.
There are two methods that we're particularly interested in.
"One is application: didFinishLaunching WithOptions".
And the second is a method you're expected to create.
In this case we're calling it setupControllers.
Now setupControllers is your central method where you track controller state and take action as appropriate to your game.
In there we're going to check the controllers array.
Next, we're going to connect and disconnect controllers. And we want to find out specifically when they connect and disconnect. So we're going to set up notifications to be notified when players do this.
And importantly, we're going to -- the action we're going to take whenever a controller connects or disconnects is to call our setupControllers method.
Lastly, we're going to setup -- we're going to kick off a wireless discovery process.
And what this does is it allows those controllers which communicate wirelessly to pair with your phone right within your game. So you don't have to exit to -- or your players don't have to exit to the settings screen in order to do that.
And importantly, notice the cascade effect here. When we kickoff wireless discovery, whenever controllers happen to be discovered, connection notifications are posted, which in turn will cascade down and call our setupControllers method.
So that's the game plan. Let's look at the code for how to do that.
We're within application: didFinishLaunching WithOptions. And you'll notice the first thing we do is we call -- or we check whether the GCController class exists.
And by extension, what we're doing here is we're checking whether the game controller framework exists in the version of the operating system that your game is running on.
This is important for those of you whose games support operating systems earlier than iOS 7 and earlier than OS X Mavericks.
(The operating systems where the game controller framework was introduced.) Assuming the game controller framework exists, then we go ahead and register for notifications whenever controllers connect and disconnect.
We do this using the notification names GCControllerDid ConnectNotification and GCControllerDid DisconnectNotification.
And you'll notice that in both of these situations, whenever these notifications are posted, we're calling setupControllers.
Lastly, we call startWirelessController Discovery WithCompletionHandler.
Now, this kicks off asynchronous scanning of wireless controllers.
When the completion handler is called, the scanning of wireless controllers has stopped.
And any controllers that are wireless that have already been discovered will have already called, or rather, posted notifications for connection.
And by association, setupControllers will have already been called.
So the important takeaway here is it's completely unnecessary to explicitly call setupControllers within the handler. Now let's look at our other method, setupControllers.
Here we're checking the controllers array.
And if it's non-empty, we take action appropriate to our game.
So that's it. That's how you find which controllers are available on your system.
Now, I'd like to offer some design guidance on how to gracefully handle connections and disconnections.
When a player connects a controller, they're communicating intent to use that controller as their preferred control scheme for your game.
And your game should react accordingly.
So, specifically, move to controller-based input.
Remove any on-screen visuals that are virtual, like virtual D-pads and analog sticks, virtual buttons.
Those are now redundant since the gamepad already has those.
Each gamepad also has a pause button. So even the little pause button overlay on the screen can be offloaded from the screen because the game controller has that. And lastly, you're going to want to set the playerIndex, which is a property on the controller. And this will light up the LEDs on the controller.
This gives important feedback to your player that this game controller is recognized and being used by your game.
And disconnections can happen for a variety of reasons. Either the player explicitly disconnects the controller, or maybe for whatever reason, the connection becomes loose or the batteries run out. In this case, as a convenience to the players, consider pausing the game play if that's appropriate for your game.
Give them an opportunity to reconnect or return to regular controls if that's an appropriate action.
Now, I'd like to focus in on the player's intent when they connect.
Some games that use tilt-and-touch control, upon entering gameplay, they present the player with this kind of an option: "Do you want to use tilt control or touch control?" And this is a great option for games to present to players.
Until they snap in a game controller.
Now, the player's intent is to use the game controller.
And this kind of a choice is actually confusing to the players.
Does this actually mean that this game doesn't support game controllers? Or does it mean that my controller isn't connected properly to my phone? Or if I select one of these options, will that disable game controller input? Instead, if you have a dialog that looks like this in your game, gate it on whether or not a controller is currently connected. If it is, that is sufficient intent that the player wishes to use game controllers. And this kind of a dialog is unnecessary.
Now, another kind of dialog you might be tempted to put up is one like this: "Game controller detected. Would you like to use it? Yes or No." And at least we're giving feedback to the player that, yes, this controller is connected and recognized. But again, the intent that the player has when they connect the controller is that they actually want to use it. And so such a dialog is redundant. If you have this kind of a dialog, you don't actually need it. Just use the controller if it's available.
And as an example of a game that does this really well, I'd like to look at Leo's Fortune.
Here it is in one of its touchscreen modes where you're controlling the main character using virtual buttons along the bottom of the screen.
This is great. We don't have a game controller attached.
And the game is very obviously presenting these control options.
Now watch what happens when we connect a controller.
The virtual buttons went away. And importantly, the player didn't have to take any action.
No dialogs were presented. No choice was given.
The game just assumes that the existence of a connected controller is intent and permission to use it.
So, we've talked about finding controllers. The next step is how do I actually read the inputs? How do I find out if the A button is being pressed? And before I get to that, let's go through and talk about what kind of inputs you're going to find on the controllers themselves.
So, first and foremost, when you're designing for game controllers, keep in mind to first design for touch.
You want the native controls of your operating system to be usable at all times. And this makes sense.
If a game player downloads your game from the App Store, they're going to have the expectation -- correctly so -- that they're able to play it regardless of whether or not they have a game controller.
So, put another way, game controllers cannot be required to play your game. Now, let's talk about profiles. So profiles are the software mapping to the hardware.
So we have three different controller types.
And they are mapped in software to two different profiles.
One is called gamepad, and the second is called extendedGamepad. And you'll notice all controllers support the gamepad profile. Now, the physical controllers, which are extended control layouts, also support the extendedGamepad.
So if you support only the gamepad profile, you're guaranteed that your game will be playable on any controller available. And if you wish to support the analog thumbsticks and the triggers, then you'll target the extendedGamepad profile as well.
So these are properties on the controller instance. Let's look at what properties are within the gamepad profile. We have buttonA, buttonB, buttonX, and buttonY. And these correspond to the four face buttons.
Similarly, the two shoulder buttons are called leftShoulder and rightShoulder in the framework. And the D-pad is simply called dpad. Now, switching over to the extended profile, extendedGamepad, it has all the same properties from gamepad and in addition, we add leftThumbstick and rightThumbstick, and leftTrigger and rightTrigger, corresponding to the additional controls that extended gamepads give us. Now I'd like to call your attention to the fact that triggers and face buttons, while physically different to the Game Controller framework, we use the same data type: GCControllerButtonInput.
Similarly, D-pads and thumbsticks, while being physically, different share the same class, called GCControllerDirectionPad.
So let's talk about those classes, buttons and D-pads. GCControllerButtonInput represents all the buttons available on the controller.
And these can be read in two ways.
One is with the pressed property. And this returns the classic, digital version of a button whether or not it's being pressed: Yes or No.
But, all buttons on game controllers are also pressure sensitive.
And if this something that's useful for your game, you read that using the value property.
This returns you a float normalized between 0 and 1 indicating how hard the button is being pressed.
Now, the A and B buttons have a special convention in iOS games and GameController games.
The A button is intended to be your primary action.
And the B button is to be used as the secondary action.
And so you need to think about, with your game: "What is my primary action? Is it jumping? Is it shooting? Is it throwing a ball?" And also, think about it in the context of UI.
If you're not in actual game play, what are the primary and secondary actions? For UI, it should be to confirm and accept for the primary action.
And the B button should be used as cancelling, the secondary action.
Let's talk about GCControllerDirectionPad now.
Again, this is used for both D-pads and thumbsticks.
And it's treated in two different ways. One is that it's treated as four buttons named Up, Down, Left and Right. And the second way we treat it is as two axes, xAxis and yAxis.
And you'll recall that I said each button on the control pad is pressure sensitive? Well, that's also true of Up, Down, Left and Right, since they're the same class.
So D-pads are effectively pressure sensitive and digital as well.
Let's look at the axis. Now axes -- the value that's returned from an axis -- is normalized between negative 1 and positive 1. And a value of 0 you can rely on being the axis at rest, meaning the player is not pressing that axis.
Now, you have a guaranteed minimum range of the unit circle.
Maximum range of the unit square.
And for those of you who may have dealt with calibration of joysticks and deadzoning before, do not do that yourself. We already take care of that for you.
So that's all the controls. And now you can get on with the business of assigning game actions to controller inputs.
And one piece of advice I can offer is a principle which a lot of games use to great effect, which is to group logically similar actions.
So in Leo's Fortune, for instance, our main character has four actions. He can walk left, right and he can jump and he can stomp.
So the developers have mapped walking left and walking right to the D-pad.
Walking left and walking right are logically similar actions. It's just walking.
And so it makes sense to group those on the D-pad.
Also, they're making good use of the D-pad's ability to readily switch directions.
Now, jumping is assigned to the A button.
This is because jumping is logically dissimilar from horizontal movement, and so it's separated.
They could have assigned jumping to the Up button, but it's a logically dissimilar action, so it might have been a little bit more confusing for players.
And, the D-pad's ability to readily switch directions could actually fight the game player in this case and result in a lot of inadvertent jumps instead of lateral movement.
Now the last ability is the stomp ability. That's been assigned to the B button. So again, logically dissimilar from walking, so we've separated it. But logically similar to jumping, so it's nearby to the A button. So now let's actually find out, now that you know which controls you want to assign to which actions in your game, let's actually go ahead and read some input.
How do you find out if the A button is pressed? Well, it's really just as simple as reading a series of properties: myController.gamepad -- gamepad being the profile -- .buttonA.pressed.
Recall that pressed gives us the Boolean state for whether the button's pressed.
In this case, we're going to fire our lasers.
Now also in our weapons code, we're going to use the B button's analog and digital representations for this portion of the game play.
If the B button is being pressed at (all in the digital sense) then we go ahead and start firing missiles at a rate that increases the harder that button is pressed; B-button .value.
Then we apply thrust to our spaceship based on whether the player is pressing the D-pad up or down.
This is perfect for the yAxis, so we're going to use the yAxis representation of the D-pad.
And note that we're not guarding this line of code with a query for whether or not the axis is pressed.
We're leveraging the fact that we can rely on the yAxis's value being 0 when the player's not pressing it.
And our applyThrust method is resilient to that and does nothing when a value of 0 is pressed. Lastly, we're taking special action if the controller that's controlling our game happens to be an extended controller.
You can check if a controller is extended merely by checking whether or not the extendedGamepad profile is nil.
Notice we weren't doing that above for gamepad, because gamepad is guaranteed to be non-nil since it's supported across all controller types.
And in this case, we're using the right thumbstick's position to move a camera in our game back and forth.
Now notice: the weapons and thrust code, we don't explicitly program for the extendedGamepad profile.
But, the extended gamepad will fall back and use the same behavior that's specified here since it's not being overridden with competing code for the extendedGamepad profile. And what this means for you is that you don't have to duplicate the same code for both gamepad and extendedGamepad if you want it to do the same thing regardless of the type of controller.
So that's one way to read controller inputs, is polling. Doing this once every game frame, typically.
The other way is using events. Sometimes you just want to be notified when something on your control pad changes.
Whether it's a button or an axis, even collections such as D-pads and thumbsticks, or profiles if you want to know if anything on the controller has changed.
And you do this by registering a block as a change handler.
Basically, "here's the code I want you to run when this input changes." So we have valueChangedHandlers. Note "value" corresponds to our querying the pressure-sensitive nature of the buttons, the float values.
And new for iOS 8, we have a pressedChangedHandler.
This is for querying digital changes.
Let's look at an example of the pressedChangedHandler.
In our game, we want to be notified whenever the Y button changes state in the digital sense.
So we've set up the pressedChangedHandler. And it's called twice, once when the button is pressed and another time when the button is released.
And you can filter that based on the pressed parameter here.
In this case, we actually care about both. So when the button is pressed, we begin charging a speed boost.
And when the button is released, we actually do the speed boost.
Now, use pressure sensitivity with discernment. There are certain times where you might be tempted to see if a trigger, for instance, is being pulled.
Don't use the analog "value" if what you really want to find out is whether or not that control is being pressed.
If so, use "pressed" instead, the Boolean representation.
Also, take advantage of the pressure-sensitivity of buttons and D-pads. D-pads, while thought of traditionally as a digital-only input, are a great way to get 360 degree movement.
So this is really important for players who have a standard gamepad without analog thumbsticks. The D-pad behaves really nicely. We spent a lot of work making it work really nicely as an analog supplement.
And Face Buttons.
You can add nuance to your game by using the pressure sensitive values. Maybe you have a soccer game and you gate how hard or soft your passes and your shots are based on how hard or soft the player taps the button.
And please remember to tell the player when you're using pressure-sensitive nature of the controls. Nothing's worse than me playing a soccer game for a week and seeing all my shots fly over the net hard and fast only to realize sometime in the future, "Oh, they're actually wanting me to use a little nuance when I'm playing the game, and I need to use a softer touch." And that relates to how are you going to be a good teacher of your controls to your player? What you see on screen here, a visual overlay that is a reference for players to know what game inputs do what in your game, is a great starting point.
But, we want to be not just a teacher, but we want to be a good teacher.
So let's look at what Leo's Fortune does.
This is the opening level. I've dropped into game play. And the first thing I see is a little floating icon over top that suggests I press left and right on the D-pad.
This is great for a number of reasons. It keeps me in the experience. The game has not paused. I don't have any overlays.
And I can move the character back and forth while this is onscreen the entire time.
It's iconic and it allows the player to progress at their own pace.
And it's out of the way. It's down in the terrain where it's not blocking my view.
After playing with that for a little bit, I come to the first portion of the level where I need to jump. And again, in a similar fashion, they kindly and gently suggest that I press the A button.
Now important to note here also, is they're not overwhelming me at the start with all the controls for the entire game.
They're introducing it in piecemeal fashion so that I can understand it, practice it and then learn the next step. All right. Where are we in the talk? I've given you an overview of game controllers.
We know which controllers are connected to our system. We know how to read the controller inputs. So now it's time to talk about what's new in iOS 8.
And I'm happy to tell you about a brand new feature called Controller Forwarding.
This allows your game controller with the snapped-in iPhone to be used as a wireless controller to control another device like an iPad or a MacBook Air.
This works over Bluetooth and Wi-Fi. And Bluetooth devices -- or sorry -- the two devices need to be signed into the same iCloud account.
Since this is a new feature, let me walk you through the flow of what happens.
So we've installed the game on the iPad. It is not installed on our phone in the controller.
We start playing it. And then through the magic of continuity, a little gamepad icon is displayed in the lower corner of the lock screen.
The player swipes up on that and a wireless connection is established.
And all the controller events are forwarded wirelessly and automatically to the gamepad -- or to the iPad, sorry. Now, which of this do you have to take responsibility for and program yourself? Absolutely nothing.
As long you're calling startWirelessController DiscoveryWith CompletionHandler, all this happens for free.
And the beauty is that the controller appears as any other in the framework.
You can read the button presses off of it.
You can find out when that controller connects and disconnects.
You can query whether it's an extended controller or a standard controller.
It just works.
Now we figured since phones have accelerometers and gyroscopes, why don't we go ahead and send that information along, too.
So this way, if your game supports motion control and game controllers, you don't need to capture that information and set up a side communication channel and serialize and de-serialize the data and then synchronize it on the other end. You don't have to worry about any of that. We take care of that for you. And all this is found in a new profile we're calling Motion.
Motion is of the class type GCMotion. So let's look at what that gives us.
Here we have four properties, gravity, user acceleration, attitude and rotation rate.
Now these are probably very familiar to those of you who have used Core Motion before.
Let's look at each of these in a little more detail. First: gravity.
Gravity is type GCAcceleration. And it returns a vector oriented in the direction in which gravity is pulling the device.
The units are in G's.
And so if the device is lying flat on a table with the screen facing up, this vector will return you a value of 0, 0, negative 1 because gravity is pointing in the exact same direction as the negative zAxis. Next we have userAcceleration.
This is used to find out inertial acceleration when the player is shaking the controller.
It excludes gravity. And the units are also in G's. So in the same scenario, when the phone is at rest on a table, the acceleration will be 0, 0, 0.
We also have attitude.
This allows you to know the 3D orientation of the device. And from that, you can determine the yaw, the pitch and the roll of the device, if that's important for your game.
Lastly we have rotation rate.
This tells you how the phone is being spun and on which axis.
And the units here are in radians per second. Now, at a high level, you're going to want to organize your code like this.
First you check the motionProfile on the controller and whether or not it's nil.
If it's non-nil, that means our controller supports motion.
And we go ahead and use that.
Otherwise, we use motion from the device.
Now, I'd like to draw your attention to the overall structure of this if-else statement. In our example, our iPad was running the game.
And the iPad has motion capabilities.
But we don't want to use those motion capabilities because that device is just sitting there on the table while we play with our phone. We want to use the phone's motion capabilities.
Hence, we prioritize that if it exists. A few notes as well.
These axes you see drawn on the screen with the iPhone, they move with the phone as it moves.
So, what in this orientation has the positive Y vector pointing straight up towards the sky, when this phone is snapped into a controller and held in landscape orientation, positive Y is now pointing to the left. So this is just something to be aware of as you're coding your game.
Also, Motion data will be jittery.
You're going to want to apply some sort of a filter to this, maybe a running average of the last x number of frames. Also new for iOS 8 is Idle Timer behavior.
The idle timer is what governs whether or not the screen turns off to save battery power. And in iOS 8, this is handled automatically for you.
Playing a game with the gamepad will keep your screen alive.
In iOS 7, you're going to want to handle this yourself.
And if you want to do that, this is what you use. You set the IdleTimerDisabled on the UIApplication instance.
Now be careful here. You also need to know when to re-enable the idle timer. And that's out of the scope of this talk, so please read the documentation on that.
Also of note is that motion apps need to do this as well.
Moving the phone does not keep the screen alive. And so regardless of which OS you're on, you have to do this if you're using motion in your game. All right. Let me talk about a little bit more guidance.
All controllers have a pause button.
So if your game supports game controllers, you have to implement a pause button handler.
This is found on controller instances. It's called controllerPausedHandler. And whenever this is called you want to treat it as a toggle. So if you're in the middle of active game play, pause the game.
If you're not -- or sorry, if your game is paused and this is called, then un-pause.
If you're in a context where pausing doesn't make sense, like a main menu, it's entirely appropriate to do nothing.
Also: Player Indicator LEDs.
Always set the -- sorry, always set the playerIndex on the controller whenever you find a controller and are about to use it.
This gives players feedback that the controller is recognized by the game and being used.
So in a single player game, it's as easy as checking the player index.
If it's unset, as denoted by this handy flag called GCControllerPlayerIndexUnset, then go ahead and set the playerIndex to 0.
This is a zero-based index. So this will light up the first LED on the control pad. Now let's talk about multiple-controller games.
In all of my examples, I'm calling self.myController.
Well, when you have a multi-player split-screen game, or a game where players are sharing the same view, you're going to have multiple controllers, so keep track of them with an array -- myController is plural.
And you want to make sure to set the playerIndex for all the controllers.
And I'll show you how to do that momentarily.
Also, consider which controllers you allow to navigate menus. It can be very confusing if you have multiple players all trying to navigate a menu at the same time competing with each other. In that case it may be appropriate to let only Player 1 control the menus.
Also, think about what a disconnection means in the context of a multi-player game.
In some games like a one-on-one tennis match, game play cannot proceed without the second player. And so in that case, we pause the game.
Other types of games with live drop-in/drop-out game play, can proceed with game play as players connect and disconnect. So in that case, you don't necessarily need to pause the game play. It can proceed.
So take whatever action is appropriate for your game.
Now let's look at a code sample. Here we are back in our friend setupControllers.
And we're looping over every controller in our array.
And for each one of those we're checking if the index is unset.
If we find even one controllerIndex that's unset, we display a player picker to the UI.
This allows them to choose which character they are in the game or to know which quadrant they're in.
And within there, we're going to set the playerIndex so that the players know what they're controlling on the screen. Now another piece of design guidance that I'd like to give you... Very important: respond to game controller inputs early.
When a player snaps in a controller and taps and launches your game from a home screen, what is the first thing they do? They start mashing the buttons, right? They start pressing the A button. They start moving the D-pad. They want to see if your game supports game controllers.
And every response you make or response your game doesn't make communicates something to the players.
And responding early tells players, yes, this game supports game controllers.
Now splash screens, introductory cinematics and the main menu at the latest are great opportunities to respond to controller inputs early.
The longer you wait and the deeper a player has to get into your game to discover the game controller integration, the more likely they are to miss-assume that this game doesn't even support game controllers and unplug their controller and just use native inputs, missing all the hard work you put into your game play. Let's look at what Leo's Fortune does.
So the game launches. It starts off with the splash screen and introductory cinematic. And pressing the A button allows you to skip the rest of that cinematic and jump straight to the main menu.
So right there, within a few seconds of launching the app, the game has told the player, yes, this game supports game controllers.
Now, at the main menu, and this is really slick, only when a game controller's attached do the green portions of the buttons glow, telling you which button on the screen is active.
By using the D-pad and navigating over, another button begins glowing instead telling you that that's the active button.
So once again, the game is confirming now, yes, this game supports game controllers.
And the player is highly likely to enter game play and enjoy the experience with the controller.
Now, another reason, if that's not enough, to mechanize your UI for game controller support is because we have standard controllers, which are standalone -- or sorry, extended standalone controllers.
These controllers, as I mentioned previously, don't have the touchscreen easily accessible.
And so all the inputs are coming exclusively from the controller.
So support mechanizing your UI so that game controllers which are standalone are supported. So what did we learn today? I gave you an overview of what the game controllers are from Apple. Basically it's a two-part -- it comes in two parts. The first part being the MFi specification, and the second part being the GameController framework. We talked about how we find controllers, how we read inputs off of those controllers.
I talked about what's new, forwarding, motion forwarding and the idle timer behavior.
And throughout we talked about design guidance: things that you can do to make the experience of game controllers really intuitive and integrated really nicely with your game so the player can just enjoy your underlying game.
For more information on game controllers, please contact Allan or Filip.
For related sessions, if you want to make a 2D game, check out the SpriteKit sessions: "What's New in SpriteKit" and "Best Practices for Building Spritekit Games." If you're interested in 3D games, check out the SceneKit presentations: "What's New in SceneKit" and "Building a Game with SceneKit." Thank you so much. I'm really excited to see what you're going to do with this.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.