Save a favorite Gamepad, and more...

GM Version: Studio 2
Target Platform: Windows
Download: see code below
Links: n/a

Summary:
This will show you the basics on how to save a preferred gamepad and assign it to any player in your game.

We all know it can be a pain to manage gamepads, especially when you plug and unplug them.
This will show you the basics on how to save a preferred gamepad and assign it to any player in your game.
The best way to use this would be to save and load from a file, but to keep things as simple as possible here, I won't go into that. There's plenty of resources on that.

I haven't refined it yet to max optimisation, so feel free to improve it for your needs, but the principle has proven to be working. Please keep in mind that while it's relatively simple, I would not file that in the beginner stuff.
You have to understand at the bare minimum arrays, loops, basic gamepad functions, and variable scope. If any of this sounds like Chinese, this is probably going to be a bit harder, as it's more of a proof of concept than something ready to implement (tho it'd be quite easy!)

The Principles:
It uses a couple of arrays to hold the players gamepad data.
Code:
global.player_gamepad
global.active_gamepad
Their configuration is as follow
Code:
global.player_gamepad[_i][0] =  //gamepad slot id

global.player_gamepad[_i][1] =  //Player i controller of choice' GUID

global.active_gamepad[_i][0] =  //gamepad slot id

global.active_gamepad[_i][1] =  //Gamepad GUID, as returned by the function gamepad_get_guid(i)
The magic is really happening in the global.player_gamepad[_i][1] variable, where it will hold the GUID of your gamepad of choice.
For those not in the know, a GUID is a unique code that identifies stuff (all kinds of stuff, not just gamepads).

Step Zero (Optional):
To me, the first logical step is to store a list of all the GUID that we ever plugged while in-game, to check if it's a new one (in case we want to assing our brand new Razer as our default gamepad).
This can be done with a simple loop as such:
GML:
function loop_gamepads_guid_all(){
    var _guid, _guid_len, _dup;
    var _i, _j;

    //Get number of gamepad inputs
    var gp_num = gamepad_get_device_count();

    //Loop through gamepads inputs
    for (_i = 0; _i < gp_num; ++_i;) {
        if gamepad_is_connected(_i) {                        //If we found a connection
            _dup = false;                                    //Reset duplilcate flag
            _guid = gamepad_get_guid(_i);                    //Get detected gamepad GUID
            _guid_len = array_length(global.arr_gp_guid_all);    ///Get the size of  our GUID array
       
            ///Loop through our GUID list to check if this controller is already in it
            for(_j=0; _j<_guid_len; _j++){
                if (global.arr_gp_guid_all[_j] == _guid){    //If we have a match
                    _dup = true;                        //Flag DUPLICATE true
                }
            }
            //Add  GUID to the end  of array if we do not have a duplicate
            if(!_dup){
            global.arr_gp_guid_all[_guid_len] = _guid;
            }
        }
    }
}
Again, this is in the minding that you would save and then load that info from somewhere, like a .ini file, for example. This is redundant otherwise and should be ignored.


Step One:
So, I know some of you are already seeing it coming together just by the description, but let's keep going.
We have to have a list of all our plugged-in gamepads and their GUID. This is quite simple. We will use the global.active_gamepad array for that.
GML:
function loop_gamepad_active(){
    var _i, _j;
    var _len;
    var _guid;
    var gp_num = gamepad_get_device_count();
    global.active_gamepad = [];                    //Resets array

    //Loop through gamepads inputs
    for (_i = 0; _i < gp_num; ++_i;) {
        if gamepad_is_connected(_i) {                //If we found a connection
            _len = array_length(global.active_gamepad);
            _guid = gamepad_get_guid(_i);
       
           global.active_gamepad[_len][0] = _i;               //This holds the gamepad slot index
           global.active_gamepad[_len][1] = _guid;        //This holds the gamepad index GUID
        }
    }
}

Oh, and by the way, if you arre wondering where you should put this script, this should be in the Async -> System, and it should look something like this
GML:
var _event = ds_map_find_value(async_load, "event_type");

switch (_event){
    case "gamepad discovered":
       //here
        break;
   
    case "gamepad lost":
       //and here
        break;
}

If you plug in a controller with this script in the async event, you should get an array that reads something like
Code:
global.active_gamepad[_len][0] = your_gamepadd_slot_index; //like 0 or 4, for example
global.active_gamepad[_len][1] = a_big_weird_string_of_letters_and_numbers;
Use the Variable window in the debugger to check if this is the case. It should update automatically as long as your game is in focus when you plug/unplug controllers.
Now we have a global array that holds all connected gamepad slot, and their GUID. This is good.


Step Two:
Now that we have an array that stores which gamepads are connected in which slot and their GUID at all time, it's time to compare if one of them matches the player's gamepad of choice.
Once again, you would probably want to load that from a file, but here we will assume there is no controller of choice assigned when the game starts. But the principles would, as always, remain the same.
So now we have to work on our next array, global.player_gamepad
Remember the array will be arranged like this:
Code:
global.player_gamepad[i][0] = //Gamepad slot
global.player_gamepad[i][1] = //Preferred gamepad GUID (loaded from file, or, like here for the example, set at -1 at  game start)
Your loop can look something like this.
GML:
function assign_gamepad_preferred_guid(_guid){
    var _i;
    var _len = array_length(global.arr_gamepads);
    var _dup = false;        //Duplicate flag
    var _len_active = array_length(global.arr_gamepad_active) -1;
 
    //Loop through our assigned gamepads
    for(_i=0; _i<_len;++_i){
        //If the GUID matches one of our preferred gamepad
        if(global.arr_gamepads[_i][1] == _guid){
            _dup = true;
            //Assign gamepad to player with this preferred gamepad
            global.arr_gamepads[_i][0] = global.arr_gamepad_active[_len_active][0];
        }
    }
 
    //If the GUID doesn't match any preferred GUID
    if(!_dup){
        //Loop through our assigned gamepads
        for(_i=0; _i<_len;++_i){
            //If no preferred GUID is detected
            if(global.arr_gamepads[_i][1] == -1){
                //Assign gamepad to player with no preference
                global.arr_gamepads[_i][0] = global.arr_gamepad_active[_len_active][0];
                //Set this controller as his default favorite gamepad
                global.arr_gamepads[_i][1] = global.arr_gamepad_active[_len_active][1];            
            }
        }            
    }
}
Now notice that this code does automatically assign a favorite gamepad if none is assigned, you will have to alter that to match your preferences and want your game to behave.

Once we have assigned our player a favorite controller, we need a function to change it/swap it between players.
Nothing is simpler to access, since we are dealing with global variables.

GML:
//Change the order of the active GUID
function swap_assigned_controller(_index_1, _index_2){
 
    var _1 = global.arr_gamepad_active[_index_1];
    var _2 = global.arr_gamepad_active[_index_2];
 
    global.arr_gamepad_active[_index_1] = _2;
    global.arr_gamepad_active[_index_2] = _1;
 
}

So there you have it.
If ever a controller becomes disconnected and reconnected, it will assign itself to the same player regardless of it's previous "slot". No more guessing games and crossing fingers that the gamepas will still work!
Save these preferences to file, and be unstoppable!
 
Last edited:
Top