Architecture For Game Controller
Table of Contents
We want to process the inputs that occur on a gamepad to change the behavior of graphic and/or sound variables.
In the example, we want to move the screen and modify the sound tone.
The first important structure is the state of each digital button on a control such as X, Y, A, B, RB, LB, etc.
Below are the structs that we will use to have controls in the game.
struct ButtonState { bool endedDown; // gamepad button is pressed int transitionCount; // how many transitions happens in one frame (up-to-down, down-to-up) };
To know if there was a button state transition, we will need to logically obtain 2 gameinputs. One for the new state and one for the old state (previous frame).
This way, whenever the frame ends, we will do a swap to identify whether the previous button was pressed and is now released and vice versa.
The controller
Below is the struct with the buttons, each button is a ButtonState
.
Our controller is made up of 12 buttons based on an Xbox controller. The control will have digital buttons + 2 sticks for the X and Y axis, as well as information on whether it accepts the analogue part and whether it is connected.
struct GameController { bool isAnalog; bool isConnected; float leftTrigger; float rightTrigger; float stickAverageX; float stickAverageY; // TODO: Add Right sticky union { ButtonState buttons[12]; struct { ButtonState btnUp; ButtonState btnRight; ButtonState btnDown; ButtonState btnLeft; ButtonState dpadUp; ButtonState dpadRight; ButtonState dpadDown; ButtonState dpadLeft; ButtonState leftShoulder; ButtonState rightShoulder; ButtonState start; ButtonState back; }; }; };
Unions in C
Within our control, we define a union
. A union is nothing more than
informing that the variables inside are pointing to the same memory
address. That is, a union:
union { int x; float y; }
This means that we have both x and y pointing to the same address, only in this case one is a float-point and the other is not.
The same happens in our control example. Both the array buttons
and
the anonymous struct GameState
are pointing to the same address.
We do this so that when we need a loop to access all the buttons, we will have an array ready for it. While when we need to individually access each button, we will also be able to do so.
Another point is that we are using an anonymous union. This means that
we can access btnUp
any other struct value as if it were a property
GameController
, let's see:
my_controller.buttons; my_controller.btnUp;
The Input
Now, we will have a last struct that will have an array of controls for us to use in the game and to swap the states in each frame.
struct GameInput { GameController controllers[4]; };
In the future, we'll use five controllers, which means the first controller is the keyboard.