Skip to main content
gamedev.net
🔒 Locked

Button Assignments

Started by TheBroodian 4 replies 1.1k views
Original Post
TheBroodian
TheBroodian
Trying to work on some sort of a button assignment system to change key bindings for controllers and keyboards. I have some sort of foggy idea about how I would do this, but I reach a point where the idea escapes me a little bit. Both direct input and Xinput's buttons correspond to an int, so it would seem simple enough to be able to attach that int to a string to symbolize the function the button has in the game (as the player prefers). But I'm a little unsure of how I would set this up.

In case I'm explaining this poorly, this is sort of how I would like it to work:

A menu queries the player to press the button he wants to use to Jump.

Player presses the button he wants to use for Jumping.

That button returns its int value corresponding to that button, and the game stores that int somewhere and correlates it to the action/function.

Anytime the button is pressed with that value, the game will relate it to the "Jump" button.

And if at a later time the player would like to do so, he can reassign the button to another function, and use a different button for Jump.
SiCrane
SiCrane
What language are you using? In C++ you can create a map from a button id to a function pointer. In C# you could create a dictionary from a button id to a delegate.
Evil Steve
Evil Steve
Moving to General Programming.
TheBroodian
TheBroodian
Excuse me, how silly of me, I'm using XNA with a wrapper for direct input.
BeerNutts
BeerNutts
I am doing something like that, except the user defines the keys he wants to use in an xml file, like this:


<Left>a</Left>
<Right>d</Right>
<Up>w</Up>
<Down>s</Down>
<Fire>MouseLButton</Fire>
<SpecialFire>MouseRButton</SpecialFire>


And, it allows the user to map a typical key action to a keyboard or a mouse button.

And, in my source file, i have these structures:


typedef enum
{
GAME_KEY_FIRST = 0,
GAME_KEY_LEFT = GAME_KEY_FIRST,
GAME_KEY_RIGHT,
GAME_KEY_UP,
GAME_KEY_DOWN,
GAME_KEY_FIRE,
GAME_KEY_SPECIAL_FIRE,
GAME_KEY_MAX

} etGameKeys;


std::string gpCfgStrings[MAX_CONFIG_OPTIONS] =
{
"Left",
"Right",
"Up",
"Down",
"Fire",
"SpecialFire",
"MouseSensitivity",
"ScreenWidth",
"ScreenHeight",
"FullScreen"
};


typedef struct
{
BOOL bMouseKey;
sf::Key::Code SfKey;
sf::Mouse::Button SFButton;

} tKeyHash;

typedef struct
{
std::string ConfigName;
tKeyHash KeyHash;

} tInputConfigNames;

// Available names for config file setting
tInputConfigNames gInputConfigNames[] =
{
{ "MouseLButton", {TRUE, sf::Key::A, sf::Mouse::Left} },
{ "MouseRButton", {TRUE, sf::Key::A, sf::Mouse::Right} },
{ "RCtrl", {FALSE, sf::Key::RControl, sf::Mouse::Left} },
{ "LCtrl", {FALSE, sf::Key::LControl, sf::Mouse::Left} },
{ "RShift", {FALSE, sf::Key::RShift, sf::Mouse::Left} },
{ "LShift", {FALSE, sf::Key::LShift, sf::Mouse::Left} },
{ "RAlt", {FALSE, sf::Key::RAlt, sf::Mouse::Left} },
{ "LAlt", {FALSE, sf::Key::LAlt, sf::Mouse::Left} },
{ "Space", {FALSE, sf::Key::Space, sf::Mouse::Left} },
{ "Return", {FALSE, sf::Key::Return, sf::Mouse::Left} },
{ "CursorRight", {FALSE, sf::Key::Right, sf::Mouse::Left} },
{ "CursorLeft", {FALSE, sf::Key::Left, sf::Mouse::Left} },
{ "CursorUp", {FALSE, sf::Key::Up, sf::Mouse::Left} },
{ "CursorDown", {FALSE, sf::Key::Down, sf::Mouse::Left} },
{ ",", {FALSE, sf::Key::Comma, sf::Mouse::Left} },
{ ".", {FALSE, sf::Key::Period, sf::Mouse::Left} },
{ "/", {FALSE, sf::Key::Slash, sf::Mouse::Left} },
{ ";", {FALSE, sf::Key::SemiColon, sf::Mouse::Left} },
{ "\'", {FALSE, sf::Key::Quote, sf::Mouse::Left} },
{ "[", {FALSE, sf::Key::LBracket, sf::Mouse::Left} },
{ "]", {FALSE, sf::Key::RBracket, sf::Mouse::Left} },
{ "\\", {FALSE, sf::Key::BackSlash, sf::Mouse::Left} }
};


/* strings for certain array locations */

tKeyHash gKeyHash[GAME_KEY_MAX] =
{
{FALSE, sf::Key::A, sf::Mouse::Left},
{FALSE, sf::Key:<img src='http://public.gamedev.net/public/style_emoticons/<#EMO_DIR#>/biggrin.gif' class='bbc_emoticon' alt=':D' />, sf::Mouse::Left},
{FALSE, sf::Key::W, sf::Mouse::Left},
{FALSE, sf::Key::S, sf::Mouse::Left},
{TRUE, sf::Key::RControl, sf::Mouse::Left},
{TRUE, sf::Key::RControl, sf::Mouse::Right},
};


I then loop through the xml file, and look for items in the gpCfgStrings array, and when they match, I call UpdateSettings():



static void UpdateSettings(C8 *pcSetting, U32 u32Option)
{
U32 u32Value;
std::string SettingStr(pcSetting);
BOOL bFoundName = FALSE;

if (u32Option >= GAME_KEY_MAX)
{
u32Value = atoi(pcSetting);
//printf("Setting option %d value %d\n", u32Option, u32Value);

if (u32Option == MOUSE_SENSITIVITY_LOC)
{
gu32MouseSens = u32Value;
}
else if (u32Option == SCREEN_WIDTH_LOC)
{
gu32ScreenWidth = u32Value;
}
else if (u32Option == SCREEN_HEIGHT_LOC)
{
gu32ScreenHeight = u32Value;
}
else
{
gbFullScreen = FALSE;

/* it's Full Screen, get Yes or No */
if (strcmp(pcSetting, "Yes") == 0)
{
printf("It's Fullscreen!\n");
gbFullScreen = TRUE;
}
}

return;
}

for(uint32_t i = 0; i < sizeof(gInputConfigNames)/sizeof(tInputConfigNames); i++)
{
if (SettingStr == gInputConfigNames.ConfigName)
{
gKeyHash[u32Option] = gInputConfigNames.KeyHash;
bFoundName = TRUE;
break;
}
}

if (!bFoundName)
{
/* it should be a single character */
C8 c8Key = pcSetting[0];

if ((c8Key >= 'a') && (c8Key <= 'z'))
{
gKeyHash[u32Option].SfKey = (sf::Key::Code)c8Key;
}
}
}


Finally, the user checks if a key is down by passing in a etGameKeys enumeration, and gets a boolen IsDown back:


BOOL Utilities::KeyIsDown(const sf::Input& Input, etGameKeys eQKey)
{
BOOL bDown = FALSE;

if (eQKey < GAME_KEY_MAX)
{
if (gKeyHash[eQKey].bMouseKey)
{
if (Input.IsMouseButtonDown(gKeyHash[eQKey].SFButton))
{
bDown = TRUE;
}
}
else
{
if (Input.IsKeyDown(gKeyHash[eQKey].SfKey))
{
bDown = TRUE;
}
}
}

return bDown;

}


So, that's how I do it in C++. Maybe you'll get an idea of how you can do this in C#/XNA.

Good Luck!
My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.