Input with the ArcadeInputManager and the GamepadManager
The point of an xplat gaming framework like Proton is to be able to say “Move the character up, if they push up” and not care if they used a joystick, gamepad, on-screen directional pad, trackball, mouse, or bluetooth keyboard or whatever the heck they invent next.
The best way to do this in Proton is to have an ArcadeInputComponent somewhere and allow this to do most of the work. Example (Also, you can look at RTLooneyLadders for a working example):
#include "Entity/ArcadeInputComponent.h" //somewhere in some init function... ArcadeInputComponent *pComp = (ArcadeInputComponent*) GetEntityRoot()->AddComponent(new ArcadeInputComponent); //make it somewhere GetBaseApp()->m_sig_arcade_input.connect(&OnArcadeInput); //connect it to a function to receive input from //Add some mappings so so the m_sig_arcade_input will get hit with it: AddKeyBinding(pComp, "Left", VIRTUAL_KEY_DIR_LEFT, VIRTUAL_KEY_DIR_LEFT); .... void OnArcadeInput(VariantList *pVList) { int vKey = pVList->Get(0).GetUINT32(); bool bIsDown = pVList->Get(1).GetUINT32() != 0; LogMsg("GameMenuArcade: Key %d, down is %d", vKey, int(bIsDown)); switch (vKey) { case VIRTUAL_KEY_DIR_LEFT: LogMsg("We got left!"); break; } }
Ok, so now pressing the LEFT arrow will show “We got left!”. Pressing the left direction on an Xperia pad will also trigger it, no special setup is required for that. But what if you also went to let people use a touch control to handle left? Easy, just have your button emit a virtual key:
Entity *pEnt = CreateOverlayButtonEntity(pBG, "left", "left_button_image.rttex", 100, 100); MakeButtonEmitVirtualGameKey(pEnt, VIRTUAL_KEY_DIR_LEFT);
Easy enough. Now this touch button will send fake virtual press/release signals through the ArcadeInputManager, so your game logic doesn't have to care where the button press came from.
The ArcadeInputManager has special code when it notices a directional key is being used and offers ways to grab info on the current direction directly with these functions:
bool GetDirectionKeysAsVector(CL_Vec2f *pVecOut); bool GetDirectionKeys(bool &bLeftOut, bool &bRightOut, bool &bUpOut, bool &bDownOut);
Ok, what if you want to connect a 360 controller via directX or an iCade controller on your iPad? The GamepadManager allows you to connect to one or many gamepads and offer multiple ways of getting data:
- You can connect it to the ArcadeInputManager so it automatically translates the left stick/pad as directional keys, and button up/down events are sent through it as well
- You can connect to the left and right stick signals and get true analog proportional controls, good for say, a 360 degree shooter
Notes:
- You can have multiple ArcadeInputManagers and connect specific gamepads/bindings to specific managers, good for say, split-screen multiplayer
- You can have an ArcadeInputManager send its messages through a specific entity via “SetOutputEntity”, instead of the global BaseApp::m_sig_arcade_input signal
- You can remove a group of key bindings from an ArcadeInputManager on the fly via “RemoveKeyBindingsStartingWith”
- GamepadManager providers can be removed/added on the fly, useful when you need to enable/disable pads flexibly
- Gamepads are pre-mapped in a universal way, instead of an “X” button on a 360, it's called VIRTUAL_KEY_DPAD_BUTTON_LEFT
Adding the GamepadManager to an existing project
Ok, let's assume you're using an ArcadeInputManager for your input and you want to add gamepad support. Here is how to add it.
Add this to your App.cpp:
//put this include near the top #include "Gamepad/GamepadManager.h" //add this under that GamepadManager g_gamepadManager; GamepadManager * GetGamepadManager() {return &g_gamepadManager;}
In App::Update(), add the following under BaseApp::Update() somewhere:
g_gamepadManager.Update();
That's it. Now, you just need to add some GamepadProvider's to the GamepadManager and you're good to go.
Here is a quick example, this would add support for Directx gamepads on Windows, and iCade sticks on everything else:
//near the top of App.cpp, add these somewhere: #ifdef PLATFORM_WINDOWS #include "Gamepad/GamepadProviderDirectX.h" #endif #include "Gamepad/GamepadProvideriCade.h" //in your App::Init() do this somewhere: #ifdef PLATFORM_WINDOWS GetGamepadManager()->AddProvider(new GamepadProviderDirectX); //use directx joysticks #endif GetGamepadManager()->AddProvider(new GamepadProvideriCade); //use iCade, this actually should work with any platform...
Next, to actually use the pads, you must connect them to the ArcadeInputComponent. Add this right after you init your ArcadeInputComponent:
//ArcadeInputComponent *pComp = (ArcadeInputComponent*)pIcon->AddComponent(new ArcadeInputComponent); //Just connect to all pads at once.. ok to do for a single player game.. otherwise, we should use //Gamepad *pPad = GetGamepadManager()->GetDefaultGamepad(); or GetUnusedGamepad() instead probably, or let the user choose. //Keep in mind pads can be removed/added on the fly for (int i=0; i < GetGamepadManager()->GetGamepadCount(); i++) { Gamepad *pPad = GetGamepadManager()->GetGamepad((eGamepadID)i); pPad->ConnectToArcadeComponent(pComp, true, true); //if we cared about the analog sticks too, we'd do this: //pPad->m_sig_left_stick.connect(1, boost::bind(&OnGamepadStickUpdate, this, _1)); //pPad->m_sig_right_stick.connect(1, boost::bind(&OnGamepadStickUpdate, this, _1)); }
That's it, now your game can be controlled by the iCade/360 pad without changing your game-specific input code at all.
To map to specific joystick buttons, you can use the following virtual keys with the ArcadeInputComponent:
VIRTUAL_DPAD_BUTTON_LEFT, VIRTUAL_DPAD_BUTTON_UP, VIRTUAL_DPAD_BUTTON_RIGHT, //generally considered a select button VIRTUAL_DPAD_BUTTON_DOWN, //generally considered a back button - map to VIRTUAL_KEY_DIR_CENTER instead for xperia play VIRTUAL_DPAD_SELECT, VIRTUAL_DPAD_START, VIRTUAL_DPAD_LBUTTON, VIRTUAL_DPAD_RBUTTON, VIRTUAL_DPAD_LTRIGGER, VIRTUAL_DPAD_RTRIGGER, VIRTUAL_DPAD_HAT_UP, //a hat is like the DPAD thingie on a 360 controller VIRTUAL_DPAD_HAT_RIGHT, VIRTUAL_DPAD_HAT_DOWN, VIRTUAL_DPAD_HAT_LEFT
Note, the VIRTUAL_DPAD_HAT_* are also handled as directional keys on a 360 controller, so the player can use the stick or the pad it.
Also, you'd have to add dinput8.lib and dxguid.lib to your “Additional dependencies” to get this to actually work with the directx part.
Conclusion
For specific instructions on setting up each kind of controller, visit the main proton page.