Game Development Community

dev|Pro Game Development Curriculum

Create different Key Bindings for differnt play modes

by Jacco Jansen · 03/17/2006 (6:59 pm) · 5 comments

Here are the key things to remember:
1. You will need a function to keep track of what mode you are in.
2. You will need to define what buttons will be used by your game
3. You need to create functionality for each play mode


I wanted to write my game is such a way that porting it to a console would be incredibly easy, so I decided to limit the amount of keys to be used in game to the amount of keys available on an XBOX joypad so the keys I would use include:
ButtonA, ButtonX, ButtonWhite, ButtonStart, DPadUp, LThumbUp, LTrigger etc etc etc.

This would be my imaginary reference image. To make this real, I went into my client/default.bind.cs file and selected keys to use ingame by replacing the current key binds with this:

moveMap.delete();
new ActionMap(moveMap);
moveMap.bindCmd(keyboard, "z", "", "toggleMovementPackage();");
moveMap.bindCmd(keyboard, "escape", "", "quit();");
moveMap.bind(keyboard, "tab", toggleFirstPerson);
moveMap.bind(keyboard, "a", buttonleft);
moveMap.bind(keyboard, "d", buttonright);
moveMap.bind(keyboard, "w", buttonup);
moveMap.bind(keyboard, "s", buttondown);
moveMap.bind(keyboard, "ctrl o", buttonStart);
moveMap.bind(keyboard, "u", buttonA);
moveMap.bind(keyboard, "i", buttonB);
moveMap.bind(keyboard, "o", buttonC);
moveMap.bind(keyboard, "n", buttonD);
moveMap.bind(keyboard, "j", buttonE);
moveMap.bind(keyboard, "k", buttonF);
moveMap.bind(keyboard, "l", buttonG);
moveMap.bind(keyboard, "m", buttonH);
moveMap.bind(mouse0, "button0", mouseFire);
moveMap.bind(mouse0, "xaxis", yaw);
moveMap.bind(mouse0, "yaxis", pitch);

exec("./scripts/KeysInBattle.cs");
exec("./scripts/KeysInRPG.cs");

//enumerations of my play modes
//needed only by choice. It makes life easier for me, personally
$RPGMode = 0;
$BattleMode = 1;

//select a default package to use upon startup and activate
//i skipped the startup screens and load stronghold immediately so I want to start in RPG mode
$activeKeyPackage = $RPGMode;
activatePackage(KeyMapRPGMode);

You will see I used the function toggleMovementPackage bound to the Z button. This is a simple script I used to swop between 2 packages. In your game you may have only 2 packages or you may have more. I would suggest something where you deselect the current package and select the one passed in via an argument. For example:

function changeToPackage(%newOne)
{
	$lastPackage = $currentPackage;
	$currentPackage = %newOne;
	deactivatePackage($lastPackage);
	activatePackage($currentPackage);
}

For my purposes I simply needed to swop so I used the code below. Also, instead of loading a new GUI, I simply hide/show elements. Will probably change his later on. Anyway, here is my code:

function setGlyphVisibility(%val)
{
	healthbar.setVisible(%val);
	energybar.setVisible(%val);
	healthbarhud.setVisible(%val);
	energybarhud.setVisible(%val);

	spellbookglyph.setVisible(%val);
	underlay.setVisible(%val);

	for (%x = 0; %x < 6; %x++)
	{
		%butglyp = "button" @ %x @ "glyph";
		%butglyp.setVisible(%val);
	}
}

function toggleMovementPackage()
{
	if ($activePackage == $BattleMode)
	{
		setGlyphVisibility(0);
		deactivatePackage(KeyMapBattleMode);
		$activePackage = $RPGMode;
	} else
	{
		setGlyphVisibility(1);
		activatePackage(KeyMapBattleMode);
		$activePackage = $BattleMode;
	}
}

Then I simply created a separate package for each game mode that exist in my game and inside all packages I created functions with the same names as the ones I bound my keys to. By doing this, changing your key mappings becomes as simple as activating the correct package.

package KeyMapBattleMode
{

function buttonleft(%val)
{
	changeSpellPage(0);
}

function buttonright(%val)
{
	changeSpellPage(2);
}

function buttonup(%val)
{
	changeSpellPage(1);
}

function buttondown(%val)
{
	changeSpellPage(3);
}

function turnLeft( %val )
{
}

function turnRight( %val )
{
}

function panUp( %val )
{
}

function panDown( %val )
{
}

function buttonA(%val)
{
	castSpell(0);
}

function buttonB(%val)
{
	castSpell(1);
}

function buttonC(%val)
{
	castSpell(2);
}

//jump function
function buttonD(%val)
{
	changeSpellBook(0);
}

//alt shoot function
function buttonE(%val)
{
	castSpell(3);
}

function buttonF(%val)
{
	castSpell(4);
}

function buttonG(%val)
{
	castSpell(5);
}

function buttonH(%val)
{
	changeSpellBook(1);
}

//options screen
function buttonStart(%val)
{
   if (%val)
      Canvas.pushDialog(OptionsDlg);
}

function yaw(%val)
{
}

function pitch(%val)
{
}

}; //package

In the above example, my movement keys do nothing (yet) since I want my characters to be visible at all times and the keys are to operate the spells being cast as this is a real time battle system. The changeSpellBook function changes between defensive and offensive spells, the changeSpellPage function selects the spells to equip and the buttons cast the spells selected. Thus at any given time any spell in your inventory is selectable in no more than 3 button presses. Rather an effective keysetup, I should think. Then I hit the Z button which calls the togglePackage function which brings up the RPG mode setup:

package KeyMapRPGMode
{

function buttonleft(%val)
{
   $mvLeftAction = %val * $movementSpeed;
}

function buttonright(%val)
{
   $mvRightAction = %val * $movementSpeed;
}

function buttonup(%val)
{
   $mvForwardAction = %val * $movementSpeed;
}

function buttondown(%val)
{
   $mvBackwardAction = %val * $movementSpeed;
}

function turnLeft( %val )
{
   $mvYawRightSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}

function turnRight( %val )
{
   $mvYawLeftSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}

function panUp( %val )
{
   $mvPitchDownSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}

function panDown(%val)
{
   $mvPitchUpSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}

//shoot function
function buttonA(%val)
{
   $mvTriggerCount0++;
}

function buttonB(%val)
{
	%item = lookForPerson();
	if (%item)
	commandToServer('AITContact');
}

function buttonC(%val)
{
	commandToServer('use',"HealthKit");
}

//jump function
function buttonD(%val)
{
   $mvTriggerCount2++;
}

//alt shoot function
function buttonE(%val)
{
   $mvTriggerCount1++;
}

function buttonF(%val)
{
}

//options screen
function buttonStart(%val)
{
   if (%val)
      Canvas.pushDialog(OptionsDlg);
}

function yaw(%val)
{
   $mvYaw += getMouseAdjustAmount(%val);
}

function pitch(%val)
{
   $mvPitch += getMouseAdjustAmount(%val);
}

};//package

Now I can move around the screen, use the mouse, shoot my mounted weapon and look for people to speak to. All by pressing one button that selects the correct package.

The only downfall to this approach is that you will always have to keep your virtual keypad in mind when doing your coding because all functions will now be named after a button rather than being descriptive. For example, you will now be using
function ButtonWhite()
instead of using
function Jump()
and
function ButtonA()
instead of
function Interact()

It is a small price to pay, in my honest opinion, but a drawback worth pointing out. The reason I say I am willing to live with it is because if you define button X to do something in one mode and want that same button to do something else in another mode, creating different functions for the same button will give one button many different function names to call and would make selection rather dubious. This way, you define a key for use in game and give that key different functions by changing the play mode...

A nice feature of this method of doing things is when you think of user customization. You can now let users change their button configuration in game using the default options screen included. All this then does is decide what button is used in the mapping stage but all functions will already be correctly mapped to all buttons no matter which they select. Bonus!

By defining certain functions but leaving them empty, you are effectively removing that button's use from the play mode. For example, imagine you are in 3rd person mode walking around town in typical RPG fassion. Then you want to climb a rope. You hit the USE button and your character mounts the rope and you enter RopeClimbMode. In this mode, you want to move up, down, climb over and drop down. All other buttons must do nothing. So create the function, leave the body empty and you are done. Simple as pie!

The easiest way to go from here, is to copy one of the packages above and save it as skeleton.txt.
Remove all functionality from the functions and save again.

In future, open it up, change the package name and save under a useful name. That is it, your buttons have been define and setup. Now all you have to do is make the functions do something and add code to activate the package when needed. Always make sure to deactivate the last package before activating the new one...

I hope this has been useful to some of you. Any comments is always welcome.

So cheers and enjoy... :D

About the author


#1
03/19/2006 (12:26 am)
Hey this is an awesome Idea
#2
03/27/2006 (6:47 pm)
Packages are neat huh? :)
#3
06/07/2006 (9:08 am)
Couldn't you just use different ActionMaps? A battle ActionMap and an RPG ActionMap and just push() and pop() them? This would save on the packages stuff and mean you could name the functions as jump() etc.
Of course it doesn't make much difference, both do the same thing and are simple to implement!
#4
07/20/2006 (10:40 pm)
Actually, this idea came to me way back when starting with Torque. I had a need, I looked for a solution, I implemented it, it worked, I was happy, I thought I'd share. :)

As any person who knows about programming will tell you, there is always more than one way to skin a cat.

If you feel confident with ActionMaps, feel free to use it. I simply found this very easy to understand/ do. If there is a way to improve upon my design, please feel free to do so and please do keep me updated. Cheers!

I am really glad this has proven useful to some, though. I posted this months ago and never saw it listed. I just descoverred it now and found I already helped someone. What a nice way to start the day :)
#5
07/21/2006 (10:11 am)
Quote:

As any person who knows about programming will tell you, there is always more than one way to skin a cat.


Isn't that the truth! I found packages confusing, so I never got into them really. The more ways to do something the better though! :)