Easier Control Maping System
by Kevin Mitchell · 04/01/2014 (9:40 am) · 31 comments
This is a system that uses the packaging functions built into the engine. I personally find this easier vs creating action maps over and over and helps for re-skinning mapped button controls to other actions and systems.
With this tutorial I will cover mapping the controller menu controls. And switching to world mappings.
First Generic Mapping:
The mapping is general and should never change. This will help control pushing and popping and not really knowing what mapped is pushed at a given time.
//Mapping Package - Title Screen
This is a general mapping skinned for the title screen. There are some un used functions but during the course for development you may find use for said mappings.
//KeyMapTitleScreen.cs
Next is the mapping system that simply switches you from on bindings to another. This can be used at the wake and sleep of what every menu we are controlling, or after a given interaction like mounting a vehicular.
//MappingSystem.cs
This is an example of my title menu and how i use the mapping to control shifting through the Menu GUI.
//mainMenuGui.cs
And if you want to see the main game mappings mine looks like this. This is activated when ever the play GUI is reactivated mind you one thing that I did change was to track the last Game play mappings to make sure that I returned to the Vehicle mapping or the Player mapping but this can easily be stored when leaving the playGui.
Game Play Mapping i use for game play, this should have all controller and keyboard functionalities tied together in one package.
The idea is to add a new "Package" Instead of adding a new bindings. This way if your layout change you change one thing and not 5000.
Hope this helps.
With this tutorial I will cover mapping the controller menu controls. And switching to world mappings.
First Generic Mapping:
The mapping is general and should never change. This will help control pushing and popping and not really knowing what mapped is pushed at a given time.
//-----------------------------------------------------------------------------
// Torque
// Copyright GarageGames, LLC 2011
//-----------------------------------------------------------------------------
echo("------------ ( RPG Move Map Activated )----------------------------------------------");
if ( isObject( rpgMoveMap ) )
rpgMoveMap.delete();
new ActionMap(rpgMoveMap);
//CONTROL WITH CONTROLER
rpgMoveMap.bind(gamepad, dpadl, RPG_L_BTN);
rpgMoveMap.bind(gamepad, dpadu, RPG_U_BTN);
rpgMoveMap.bind(gamepad, dpadd, RPG_D_BTN);
rpgMoveMap.bind(gamepad, dpadr, RPG_R_BTN);
rpgMoveMap.bind( gamepad, thumbrx, "D", "-0.05 0.05", RPG_YAW_X );
rpgMoveMap.bind( gamepad, thumbry, "D", "-0.05 0.05", RPG_PITCH_Y );
rpgMoveMap.bind( gamepad, thumblx, "D", "-0.05 0.05", RPG_MOVE_X );
rpgMoveMap.bind( gamepad, thumbly, "D", "-0.05 0.05", RPG_MOVE_Y );
rpgMoveMap.bind( gamepad, btn_l, RPG_L1_Trigger);
rpgMoveMap.bind( gamepad, btn_r, RPG_R1_Trigger);
rpgMoveMap.bind( gamepad, triggerl, RPG_L2_Trigger);
rpgMoveMap.bind( gamepad, triggerr, RPG_R2_Trigger);
rpgMoveMap.bind( gamepad, btn_lt, RPG_L3_Trigger);
rpgMoveMap.bind( gamepad, btn_rt, RPG_R3_Trigger);
rpgMoveMap.bind( gamepad, btn_back, RPG_Select );
rpgMoveMap.bind( gamepad, btn_start, RPG_Start );
rpgMoveMap.bind( gamepad, btn_a, RPG_A_BTN );
rpgMoveMap.bind( gamepad, btn_b, RPG_B_BTN );
rpgMoveMap.bind( gamepad, btn_x, RPG_X_BTN );
rpgMoveMap.bind( gamepad, btn_y, RPG_Y_BTN );
//CONTROL WITH KEYBOARD
rpgMoveMap.bind( keyboard, left, RPG_L_BTN );
rpgMoveMap.bind( keyboard, right, RPG_R_BTN );
rpgMoveMap.bind( keyboard, up, RPG_U_BTN );
rpgMoveMap.bind( keyboard, down, RPG_D_BTN );
rpgMoveMap.bind( keyboard, a, moveleft );
rpgMoveMap.bind( keyboard, d, moveright );
rpgMoveMap.bind( keyboard, w, moveforward );
rpgMoveMap.bind( keyboard, s, movebackward );
rpgMoveMap.bind( mouse, xaxis, yaw );
rpgMoveMap.bind( mouse, yaxis, pitch );
rpgMoveMap.bind( keyboard, space, RPG_X_BTN );
rpgMoveMap.bind( keyboard, q, RPG_L1_Trigger);//Quick Bar
rpgMoveMap.bind( keyboard, f, RPG_R1_Trigger);//Lock On
rpgMoveMap.bind( keyboard, lshift, RPG_L2_Trigger);//Sprint Trigger NOT WORKING
rpgMoveMap.bind( keyboard, e, RPG_R2_Trigger);//unused
rpgMoveMap.bind( keyboard, c, RPG_L3_Trigger);//Change Player
rpgMoveMap.bind( keyboard, tab, RPG_R3_Trigger);//Change Camera
rpgMoveMap.bind( keyboard, escape, RPG_Start );
rpgMoveMap.bind( keyboard, enter, RPG_A_BTN );//Attack Select
rpgMoveMap.bind( keyboard, backspace, RPG_B_BTN );//Cancel
rpgMoveMap.bind( mouse, button0, RPG_A_BTN );//Cancel
rpgMoveMap.bind( mouse, button1, RPG_B_BTN);//Attack
rpgMoveMap.bind( mouse, button2, RPG_Y_BTN );//Special//Mapping Package - Title Screen
This is a general mapping skinned for the title screen. There are some un used functions but during the course for development you may find use for said mappings.
//KeyMapTitleScreen.cs
package KeyMapTitleScreen
{
function RPG_U_BTN(%val)
{
if(%val)MainMenuGui::Up();
}
function RPG_D_BTN(%val)
{
if(%val)MainMenuGui::Down();
}
function RPG_L_BTN(%val){}
function RPG_R_BTN(%val){}
function RPG_YAW_X(%val){}
function RPG_PITCH_Y(%val){}
function RPG_MOVE_X(%val){}
function RPG_MOVE_Y(%val){}
function RPG_A_BTN(%val)
{
if(%val)MainMenuGui::Select();
}
//jump function
function RPG_B_BTN(%val){}
function RPG_X_BTN(%val){}
function RPG_Y_BTN(%val){}
function RPG_L1_Trigger(%val){}
function RPG_R1_Trigger(%val){}
function RPG_L2_Trigger(%val){}
function RPG_R2_Trigger(%val){}
function RPG_L3_Trigger(%val){}
function RPG_R3_Trigger(%val){}
function RPG_Select(%val){}
function RPG_Start(%val){
if(%val && $IN_WORLD_EDITOR)toggleEditor( true );
}
//System Fucntions
function gamePadMoveX( %val ){}
function gamePadMoveY( %val ){}
function gamepadYaw(%val){}
function gamepadPitch(%val){}
//KEYBOARD INJECTION
function moveleft(%val){}
function moveright(%val){}
function moveforward(%val){}
function movebackward(%val){}
function moveup(%val){}
function movedown(%val){}
function turnLeft( %val ){}
function turnRight( %val ){}
function panUp( %val ){}
function panDown( %val ){}
};//packageNext is the mapping system that simply switches you from on bindings to another. This can be used at the wake and sleep of what every menu we are controlling, or after a given interaction like mounting a vehicular.
//MappingSystem.cs
//Used when all input needs to be disabled
$KEY::NullMode = 0;
//
$KEY::TitleMode = 1;
$KEY::RPGMode = 2;
$KEY::PauseMode = 3;
$KEY::GOMode = 4;
$KEY::QBARMode = 5;
$KEY::EventNavigation = 6;
$KEY::KeyMapItemStoreOptions = 7;
$KEY::KeyMapItemStoreSelectList = 8;
$KEY::KeyMapItemStoreTotal = 9;
$KEY::KeyMapItemStoreSellSelectList = 10;
$KEY::KeyMapItemStoreSellTotal = 11;
$KEY::KeyMapSaveGame = 12;
$KEY::KeyMapInnStoreOptions = 13;
$KEY::CutSceenControls = 14;
$KEY::CarControls = 15;
$KEY::KeyMapBattleMode = 16;
$KEY::KeyMapWorldEDTMode = 17;
$activeKeyPackage = $KEY::TitleMode;
function changeToPackage(%newOne)
{
$lastPackage = $activeKeyPackage;
$activeKeyPackage = %newOne;
switch($lastPackage)
{
case $KEY::NullMode:
deactivatePackage(KeyMapNull);
rpgMoveMap.pop();
case $KEY::TitleMode:
deactivatePackage(KeyMapTitleScreen);
rpgMoveMap.pop();
case $KEY::RPGMode:
deactivatePackage(KeyMapRPGMode);
rpgMoveMap.pop();
case $KEY::PauseMode:
deactivatePackage(KeyMapPauseMenuMain);
rpgMoveMap.pop();
case $KEY::KeyMapWorldEDTMode:
deactivatePackage(KeyMapWorldEDTMode);
rpgMoveMap.pop();
default :
error("------INVALID MAP SENT----------");
}
switch($activeKeyPackage)
{
case $KEY::NullMode:
activatePackage(KeyMapNull);
rpgMoveMap.push();
case $KEY::TitleMode:
activatePackage(KeyMapTitleScreen);
rpgMoveMap.push();
case $KEY::RPGMode:
activatePackage(KeyMapRPGMode);
rpgMoveMap.push();
case $KEY::PauseMode:
activatePackage(KeyMapPauseMenuMain);
rpgMoveMap.push();
case $KEY::KeyMapWorldEDTMode:
activatePackage(KeyMapWorldEDTMode);
rpgMoveMap.push();
default :
error("------INVALID MAP SENT----------");
}
}This is an example of my title menu and how i use the mapping to control shifting through the Menu GUI.
//mainMenuGui.cs
$TITLE::INDEX=0;
//------------------------------------------------------------------------------
function MainMenuGui::onAdd(%this)
{
$TITLE::INDEX=0;
}
//------------------------------------------------------------------------------
function MainMenuGui::onWake(%this)
{
// Play sound...
$enableDirectInput = "1";
activateDirectInput();
enableJoystick();
TITLE_2DIMAGE.visible=(!$LEVELTYPE::USING_3D_MENU);
//playEnvMusic("TitleScreenTheme.ogg",3);
changeToPackage($KEY::TitleMode);
}
//------------------------------------------------------------------------------
function MainMenuGui::onSleep(%this)
{
// Clear the load info:
// Stop sound...
changeToPackage($KEY::NullMode);
playEnvMusic("",0);
TITLE_LIST.clear();
}
function TITLE_LIST::onWake(%this)
{
if(TITLE_LIST.getRowCount()==0){
%this.addRow("NEW GAME", "startNewGame", 0);
%this.addRow("LOAD GAME", "openLoadMenu", 2, -15);
%this.addRow("OPTIONS", "openOptionsMenu", 4, -15);
%this.addRow("EXIT GAME", "quit", 6, -15);
}
}
function MainMenuGui::Up(){
$TITLE::INDEX--;
if($TITLE::INDEX<0)$TITLE::INDEX=2;
TITLE_LIST.setSelected($TITLE::INDEX);
}
function MainMenuGui::Down(){
$TITLE::INDEX++;
if($TITLE::INDEX>=3)$TITLE::INDEX=0;
TITLE_LIST.setSelected($TITLE::INDEX);
}
function openOptionsMenu(){
Canvas.pushDialog(RPGoptionsDlg);
}
function MainMenuGui::Select(){
TITLE_LIST.activateRow();
}And if you want to see the main game mappings mine looks like this. This is activated when ever the play GUI is reactivated mind you one thing that I did change was to track the last Game play mappings to make sure that I returned to the Vehicle mapping or the Player mapping but this can easily be stored when leaving the playGui.
function SavePlayPackage(){
$PlayGuiParentPackage=$activeKeyPackage;
changeToPackage($KEY::$KEY::PauseMode);
}
function RestorePlayPackage(){
if($PlayGuiParentPackage>$KEY::NullMode){
changeToPackage($PlayGuiParentPackage);
}else{
changeToPackage($KEY::RPGMode);
}
}Game Play Mapping i use for game play, this should have all controller and keyboard functionalities tied together in one package.
package KeyMapRPGMode
{
function RPG_U_BTN(%val)
{
if(%val)toggleHover(0);
}
function RPG_D_BTN(%val){}
function RPG_L_BTN(%val){}
function RPG_R_BTN(%val){}
function RPG_YAW_X(%val)
{
gamepadYaw(%val);
}
function RPG_PITCH_Y(%val)
{
gamepadPitch(%val);
}
function RPG_MOVE_X(%val)
{
gamePadMoveX(%val);
}
function RPG_MOVE_Y(%val)
{
gamePadMoveY(%val);
}
function RPG_A_BTN(%val)
{
if(%val){
switch$($PLAYER::PlayerInteractionCheck){
case $Interaction::ItemStore :
Canvas.setContent(ItemStore);
case $Interaction::ArmorStore :
case $Interaction::WeaponStore :
case $Interaction::NPC :
if(isObject($PLAYER::InteractNPC) && $PlayerObject::ScanEnabled==true){
PL_Interaction_IMG.visible=false;
StopScan();
$PLAYER::InteractNPC.PROCESS_EVENTS();
$PLAYER::InteractNPC.PrevState = $PLAYER::InteractNPC.CurrentState;
$PLAYER::InteractNPC.CurrentState = $NPC::Idle;
$PLAYER::InteractNPC=0;
}
case $Interaction::TreasureChest :
case $Interaction::BattleGrounds :
}
}
}
function RPG_B_BTN(%val){}
//jump function
function RPG_X_BTN(%val)
{
$mvTriggerCount2++;
}
function RPG_Y_BTN(%val){}
function RPG_L1_Trigger(%val){}
function RPG_R1_Trigger(%val){}
//Custom Trigger
function RPG_L2_Trigger(%val){
if(%val)$mvTriggerCount5++;
}
function RPG_R2_Trigger(%val){
if(%val)$mvTriggerCount1++;
}
function RPG_L3_Trigger(%val){
switchPlayer(%val);
}
function RPG_R3_Trigger(%val){
toggleFirstPerson(%val);
}
function RPG_Select(%val){}
function RPG_Start(%val){
if(%val && $IN_WORLD_EDITOR){
toggleEditor( true );
}else{
if(%val){
$PAUSING_GAME=true;
Canvas.setContent(PauseMenu);
}
}
}
//System Fucntions
function gamePadMoveX( %val )
{
if(%val){
$RPG_PLAYER_MOVING=1;
}else{
$RPG_PLAYER_MOVING=0;
}
%MoveVel = getMoveAdjustAmount(%val);
commandToServer('setAttackingX',%MoveVel);
//if($LOCK::ON)%MoveVel/=2;
if(%MoveVel > 0)
{
$mvRightAction = %MoveVel;
$mvLeftAction = 0;
}
else
{
$mvRightAction = 0;
$mvLeftAction = -%MoveVel;
}
}
function gamePadMoveY( %val )
{
if(%val){
$RPG_PLAYER_MOVING=1;
}else{
$RPG_PLAYER_MOVING=0;
}
%MoveVel = getMoveAdjustAmount(%val);
commandToServer('setAttackingY',%MoveVel);
if(%MoveVel > 0)
{
$mvForwardAction = %MoveVel;
$mvBackwardAction = 0;
}
else
{
$mvForwardAction = 0;
$mvBackwardAction = -%MoveVel;
}
}
function gamepadYaw(%val)
{
if($LOCK::ON)return;
%yawAdj = getGamepadAdjustAmount(%val);
if(ServerConnection.isControlObjectRotDampedCamera())
{
// Clamp and scale
%yawAdj = mClamp(%yawAdj, -m2Pi()+0.01, m2Pi()-0.01);
%yawAdj *= 0.5;
}
if(%yawAdj > 0)
{
$mvYawLeftSpeed = %yawAdj;
$mvYawRightSpeed = 0;
}
else
{
$mvYawLeftSpeed = 0;
$mvYawRightSpeed = -%yawAdj;
}
}
function gamepadPitch(%val)
{
%pitchAdj = getGamepadAdjustAmount(%val);
if(ServerConnection.isControlObjectRotDampedCamera())
{
// Clamp and scale
%pitchAdj = mClamp(%pitchAdj, -m2Pi()+0.01, m2Pi()-0.01);
%pitchAdj *= 0.5;
}
if(%pitchAdj > 0)
{
$mvPitchDownSpeed = %pitchAdj;
$mvPitchUpSpeed = 0;
}
else
{
$mvPitchDownSpeed = 0;
$mvPitchUpSpeed = -%pitchAdj;
}
}
//KEYBOARD INJECTION
function moveleft(%val)
{
if(%val){
$RPG_PLAYER_MOVING=1;
}else{
$RPG_PLAYER_MOVING=0;
}
commandToServer('setAttackingX',-1);
$mvLeftAction = %val * $movementSpeed;
}
function moveright(%val)
{
if(%val){
$RPG_PLAYER_MOVING=1;
}else{
$RPG_PLAYER_MOVING=0;
}
commandToServer('setAttackingX',1);
$mvRightAction = %val * $movementSpeed;
}
function moveforward(%val)
{
if(%val){
$RPG_PLAYER_MOVING=1;
}else{
$RPG_PLAYER_MOVING=0;
}
commandToServer('setAttackingY',1);
$mvForwardAction = %val * $movementSpeed;
}
function movebackward(%val)
{
if(%val){
$RPG_PLAYER_MOVING=1;
}else{
$RPG_PLAYER_MOVING=0;
}
commandToServer('setAttackingY',-1);
$mvBackwardAction = %val * $movementSpeed;
}
function moveup(%val)
{
%object = ServerConnection.getControlObject();
if(%object.isInNamespaceHierarchy("Camera"))
$mvUpAction = %val * $movementSpeed;
}
function movedown(%val)
{
%object = ServerConnection.getControlObject();
if(%object.isInNamespaceHierarchy("Camera"))
$mvDownAction = %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;
}
};//packageThe idea is to add a new "Package" Instead of adding a new bindings. This way if your layout change you change one thing and not 5000.
Hope this helps.
About the author
Riding Solo since 2005. Current Project: Fated World 2005-Present RPG Engine Tool Kit - Now available.
#22
$KEY::KeyMapItemStoreOptions
$KEY::KeyMapItemStoreSelectList
$KEY::KeyMapItemStoreTotal
$KEY::KeyMapItemStoreSellSelectList
$KEY::KeyMapItemStoreSellTotal
07/01/2014 (2:23 am)
You have to add the support for the mapping in the switch statement for the following mappings. $KEY::KeyMapItemStoreOptions
$KEY::KeyMapItemStoreSelectList
$KEY::KeyMapItemStoreTotal
$KEY::KeyMapItemStoreSellSelectList
$KEY::KeyMapItemStoreSellTotal
#23

This is a visual of what is going on.
You are maping your controls once.
Example:
Then to change what the RPG_A_BTN function does we have packages. A package will enable the definition of what RPG_A_BTN does.
So we have a package for Title Screen, Open World, and Store
So any time you make a new mapping for any thing you need to add that new map to the switch statement.
If we look at the switch statement there is one for deacticating one package and activating another.
The above will deactivate the package that defines what RPG_A_BTN,RPG_B_BTN,RPG_X_BTN, etc, will do.
Then:
The above will activate a new mapping that defines what RPG_A_BTN,RPG_B_BTN,RPG_X_BTN, etc, will do.
If you change your package to a mapping that is not defined in your switch statement then you will get:
------INVALID MAP SENT----------
Because you have not added support for those new packages in your function.
07/01/2014 (2:53 am)

This is a visual of what is going on.
You are maping your controls once.
Example:
rpgMoveMap.bind( gamepad, btn_a, RPG_A_BTN ); rpgMoveMap.bind( gamepad, btn_b, RPG_B_BTN ); rpgMoveMap.bind( gamepad, btn_x, RPG_X_BTN ); rpgMoveMap.bind( gamepad, btn_y, RPG_Y_BTN );
Then to change what the RPG_A_BTN function does we have packages. A package will enable the definition of what RPG_A_BTN does.
So we have a package for Title Screen, Open World, and Store
So any time you make a new mapping for any thing you need to add that new map to the switch statement.
If we look at the switch statement there is one for deacticating one package and activating another.
case $KEY::TitleMode:
deactivatePackage(KeyMapTitleScreen);
rpgMoveMap.pop();The above will deactivate the package that defines what RPG_A_BTN,RPG_B_BTN,RPG_X_BTN, etc, will do.
Then:
case $KEY::RPGMode:
activatePackage(KeyMapRPGMode);
rpgMoveMap.push();The above will activate a new mapping that defines what RPG_A_BTN,RPG_B_BTN,RPG_X_BTN, etc, will do.
If you change your package to a mapping that is not defined in your switch statement then you will get:
------INVALID MAP SENT----------
Because you have not added support for those new packages in your function.
#24
My next question is dealing with the different parts of the GUI components like; slider, tabs, drop down menu, etc.. A good example would be the Options gui. How would you change tabs from Graphics to Audio?
EDIT: I actually looked at the T3D example from TGEA 1.8.1 and so far it's working.
07/01/2014 (6:24 am)
I had to redo my project so now I have Main menu working again with the controller. Looking at your diagram it made more sense. Now I should be able to get your example menus working. Thank you for explaining in detail.My next question is dealing with the different parts of the GUI components like; slider, tabs, drop down menu, etc.. A good example would be the Options gui. How would you change tabs from Graphics to Audio?
EDIT: I actually looked at the T3D example from TGEA 1.8.1 and so far it's working.
#25
07/02/2014 (12:01 am)
I need help with trying to select a mission to host. I'm using the menu like the options from the T3D demo from TGEA 1.8.2
#26
07/02/2014 (3:13 am)
I've never done server client MMO maps.
#27
07/02/2014 (3:16 am)
Well what I'm trying to do is make the default T3D Menus enabled for controller support. I'm at the Choose Level gui and trying to figure out how to select a level, check mark to host, and launch the mission.
#28
Then when you hit left or right you move the hi-light to the next object.
07/02/2014 (3:27 am)
Ah you might need to find out if you can set the object to make it look selected. So when you load the GUI you set the first map in the list to hilighted mode and store the index of your current position. Then when you hit left or right you move the hi-light to the next object.
#29
07/02/2014 (3:30 am)
I was looking at the T3D from TGEA 1.8.2 and you can select your player model and weapon. I was wondering if you could do the same thing like that. But instead of viewing the 3D model you view a image of the mission and remove the weapon select.
#30
07/02/2014 (3:54 am)
That uses a 3d object viewer. You want a image object it sounds like. Unless you are planning on loading one mesh that represents your level.
#31
07/02/2014 (4:23 am)
No, just a plain image would be just fine. I'm just trying to figure out how to do this. 
Torque Owner Stephen
GearedMind Studio