How can I assign different Gamepad Slot numbers to different global variables?

Every tutorial or example I can possibly find to do with handling multiple gamepads have Async>System event code that creates objPlayer's.

Instead, how do I assign the pad_num slots to individual obj_Player1 and obj_Player2 without instance_creating them through the Async event?

What I'm trying to do is to use a variable like pad_num for a slot so Gamemaker Studio always detects the right slot for each obj_Player1 and obj_Player2. If I use gamepad_button_check(0, face1), of course that's going to work for player one, but for player two gamepad_button_check(1, face1) may not work if Player2's gamepad slot that was assigned wasn't "1".

So Ideally, how do I have obj_Player1 and obj_Player2 detect their own pad_num slots through the Async>System event, so gamepad_button_check(pad_num, face1) works for both obj_Player1 and obj_Player2 without doing code from tutorials that involve creating the obj_Player1 instances through it's Async>System event. My obj_Player1 and obj_Player2 are already placed inside the rooms already.

EDIT:
Basically how can I make 2 different global variables for slot numbers that are detected, so that no matter what type of gamepad is plugged in say it goes to slot 10, I can have a global.Slot2.

How do I have code like that, that can detect new gamepads and assign them to:

global.Slot1
global.Slot2

then I can gamepad_button_check(global.Slot2, gp_face1)?
 
Last edited:

chirpy

Member
I'm not sure I 100% understood your question, but it sounds like you want a mapping from player index to corresponding gamepad index.
It can be done using an 1d array, say:
global.player_gamepads[0] = 4, global.player_gamepads[1] = 3

A ds_map is also good for this scenario.
Games usually create the mappings during the character selection screen, which is why players usually need to confirm they're ready before a multiplayer game starts.
 
Ok I'm still confused though, I would I incorporate that code into this async>system event?

Code below:
GML:
/// @description Detect Gamepads

// Debug code so you can see which event has been
// triggered and the pad associated with it.
show_debug_message("Event = " + async_load[? "event_type"]);
show_debug_message("Pad = " + string(async_load[? "pad_index"]));

// Parse the async_load map to see which event has been triggered
switch(async_load[? "event_type"])
{
// A game pad has been discovered
case "gamepad discovered":
  // Get the pad index value from the async_load map
  var pad = async_load[? "pad_index"];
  // Set the "deadzone" for the axis
  gamepad_set_axis_deadzone(pad, 0.5);
  // Set the "threshold" for the triggers
  gamepad_set_button_threshold(pad, 0.1);

// Gamepad has been removed or otherwise disabled
case "gamepad lost":
  // Get the pad index
  var pad = async_load[? "pad_index"];
  // Check for a player instance associated with the pad and remove it

}
 

chirpy

Member
Hi, sorry I haven't used async gamepad detection before, so here's only my guesswork and pseudocode.
What I meant by a "map" is a data structure you keep, to store a mapping from player_index to gamepad_index.
So, to support say a max of 2 players:
GML:
// init
#macro k_max_players 2
global.player_gamepads = array_create(k_max_players);

global.player_gamepads[0] = noone; // meaning player 0 has no gamepad detected yet
global.player_gamepads[1] = noone;
On "gamepad discovered", you check to see who's the first player that has no gamepad and assign the mapping.
Code:
for (var i=0; i<k_max_players; ++i) {
   if (global.player_gamepads[i] == noone) {
       global.player_gamepads[i] = async_load[? "pad_index"];
       break;
   }
}
On "gamepad lost", you check to see who's the gamepad owner and reset the pad_index to noone.
Code:
for (var i=0; i<k_max_players; ++i) {
   if (global.player_gamepads[i] == async_load[? "pad_index"]) {
       global.player_gamepads[i] = noone;
       break;
   }
}
Then you can use
Code:
 gamepad_button_check(global.player_gamepads[0], gp_face1)
to check for your first player's gamepad input.
Be sure to check for
Code:
 if (global.player_gamepads[0] != noone)
before calling button checks.
 
Ok so I believe I've done everything you've said here and it won't detect a gamepad button.

The gamepad works if I use the pad index of 0 as in:

gamepad_button_check(0, gp_face1)

but it does NOT work for
gamepad_button_check(global.player_gamepads[0], gp_face1)


I put your // init code in a create event in an object in the first room.

This is what I have for the Async>System event:
GML:
// @description Detect Gamepads

// Debug code so you can see which event has been
// triggered and the pad associated with it.
show_debug_message("Event = " + async_load[? "event_type"]);
show_debug_message("Pad = " + string(async_load[? "pad_index"]));

// Parse the async_load map to see which event has been triggered
switch(async_load[? "event_type"])
{
// A game pad has been discovered
case "gamepad discovered":
  // Get the pad index value from the async_load map
  var pad = async_load[? "pad_index"];
  for (var i=0; i<k_max_players; i++;) {
   if (global.player_gamepads[i] == noone) {
       global.player_gamepads[i] = async_load[? "pad_index"];
       break;
   }
}
  // Set the "deadzone" for the axis
///  gamepad_set_axis_deadzone(pad, 0.5);
  // Set the "threshold" for the triggers
///  gamepad_set_button_threshold(pad, 0.1);

// Gamepad has been removed or otherwise disabled
case "gamepad lost":
  // Get the pad index
  var pad = async_load[? "pad_index"];
  for (var i=0; i<k_max_players; i++;) {
   if (global.player_gamepads[i] == async_load[? "pad_index"]) {
       global.player_gamepads[i] = noone;
       break;
   }
}
  // Check for a player instance associated with the pad and remove it

}

Any ideas?
 
It looks like you're just missing the break statements at the end of each case, so you're assigning the gamepad and then immediately falling through to next case and un-assigning it.

It should look something like this:

GML:
// Parse the async_load map to see which event has been triggered
switch(async_load[? "event_type"]) {
    
    // A game pad has been discovered
    case "gamepad discovered":
    
        // Get the pad index value from the async_load map
        var pad = async_load[? "pad_index"];
        
        // find the first player with no assigned gamepad
        for (var i=0; i<k_max_players; i++;) {
            
            if (global.player_gamepads[i] == noone) {
                
                show_debug_message("Assigned Pad " + string(pad) + " to Player " + string(i));
                
                //assign pad to player and set deadzones
                global.player_gamepads[i] = async_load[? "pad_index"];
                gamepad_set_axis_deadzone(pad, 0.5);
                gamepad_set_button_threshold(pad, 0.1);
                
                break; // end for
            }
            
        }
        
        break;  // end gamepad connected case

    // Gamepad has been removed or otherwise disabled
    case "gamepad lost":
    
        // Get the pad index
        var pad = async_load[? "pad_index"];
        
        //find the player this pad is assigned to
        for (var i=0; i<k_max_players; i++;) {
            
            if (global.player_gamepads[i] == async_load[? "pad_index"]) {
                
                //un-assign the pad
                show_debug_message("Disconnected Pad " + string(pad) + " from Player " + string(i));
                global.player_gamepads[i] = noone;
                
                break; // end for
            }
            
        }

        break; // end gamepad lost case
}
Now you should be able to properly reference the gamepads assigned to global.player_gamepad[x].
 
Brilliant it works, thank you both sooooo much, I never would've been able to figure this out without you two. Works like a charm.
 
Hey, I've been looking for a way to do exactly what you're talking about here for a long time, but for some reason it's not working.

I put the Async code in the Async System Event for "o_game" (the main persistent object).

I see in the debug messsage that it says the pad index has been assigned to player 0, but the player is not getting input.

By the way, I changed "global.player_gamepads[ ]" to "global.Controller_Slot[ ]".

Async System in o_game:
GML:
// Parse the async_load map to see which event has been triggered
switch(async_load[? "event_type"]) {
    
    // A game pad has been discovered
    case "gamepad discovered":
    
        // Get the pad index value from the async_load map
        var pad = async_load[? "pad_index"];
        
        // find the first player with no assigned gamepad
        for (var i=0; i<k_max_players; i++;) {
            
            if (global.Controller_Slot[i] == noone) {
                
                show_debug_message("Assigned Pad " + string(pad) + " to Player " + string(i));
                
                //assign pad to player and set deadzones
                global.Controller_Slot[i] = async_load[? "pad_index"];
                gamepad_set_axis_deadzone(pad, 0.5);
                gamepad_set_button_threshold(pad, 0.1);
                
                break; // end for
            }
            
        }
        
        break;  // end gamepad connected case

    // Gamepad has been removed or otherwise disabled
    case "gamepad lost":
    
        // Get the pad index
        var pad = async_load[? "pad_index"];
        
        //find the player this pad is assigned to
        for (var i=0; i<k_max_players; i++;) {
            
            if (global.Controller_Slot[i] == async_load[? "pad_index"]) {
                
                //un-assign the pad
                show_debug_message("Disconnected Pad " + string(pad) + " from Player " + string(i));
                global.Controller_Slot[i] = noone;
                
                break; // end for
            }
            
        }

        break; // end gamepad lost case
}
I put the init code in o_game Create:

GML:
// init
#macro k_max_players 4
global.Controller_Slot = array_create(k_max_players);

global.Controller_Slot[0] = noone; // meaning player 0 has no gamepad detected yet
global.Controller_Slot[1] = noone;
global.Controller_Slot[2] = noone;
global.Controller_Slot[3] = noone;
and the gamepad code like so:

GML:
action_one_   = gamepad_button_check(global.Controller_Slot[0], gp_face1);
action_two_   = gamepad_button_check(global.Controller_Slot[0], gp_face2);
action_three_ = gamepad_button_check(global.Controller_Slot[0], gp_face3);
action_four_  = gamepad_button_check(global.Controller_Slot[0], gp_face4);
 
Top