Skip to content

Configurable Game Controller Mappings

Benjamin Schulte edited this page Nov 28, 2017 · 16 revisions

Installation

Add the dependency to your core project:

compile "de.golfgl.gdxcontrollerutils:gdx-controllerutils-mapping:$cuversion"

Usage

Make sure that you have read and understood Documentation on libGDX' controller interface. This extension provides a configurable mapping on top of that.

The main class of this extension is ControllerMappings. At the creation of your game, you have to instantiate this class (or a subclass of it).

public class MyGame extends Game {
    public ControllerMappings controllerMappings;

    @Override
    public void create() {
        //...
        controllerMappings = new MyControllerMappings();
    }
}

public class MyControllerMapping extends ControllerMappings {
    // we fill this soon
}

Defining the buttons and axis your game needs

Each game needs different controller buttons and axis. While retro games will work best with a D-Pad and up to four buttons, others will need two analog axis to work. You define the needed input types by instantiating a ConfiguredInput object. Its constructor takes the type of the input (button, analog axis, digital axis or digital or analog axis) and a unique identification number for this input:

public static final int BUTTON_JUMP = 0;
new ConfiguredInput(ConfiguredInput.Type.button, BUTTON_JUMP)

Add such configured inputs by calling addConfiguredInput() of ControllerMappings. For example, the following calls define a good old NES-style gamepad. They are best placed in MyControllerMapping's constructor:

public static final int BUTTON_JUMP = 0;
public static final int BUTTON_FIRE = 1;
public static final int AXIS_VERTICAL = 2;
public static final int AXIS_HORIZONTAL = 3;
public static final int BUTTON_START = 4;
public static final int BUTTON_CANCEL = 5;

public MyControllerMapping() {
    super();

    addConfiguredInput(new ConfiguredInput(ConfiguredInput.Type.button, BUTTON_JUMP));
    addConfiguredInput(new ConfiguredInput(ConfiguredInput.Type.button, BUTTON_FIRE));
    addConfiguredInput(new ConfiguredInput(ConfiguredInput.Type.button, BUTTON_START));
    addConfiguredInput(new ConfiguredInput(ConfiguredInput.Type.button, BUTTON_CANCEL));
    addConfiguredInput(new ConfiguredInput(ConfiguredInput.Type.axisDigital, AXIS_VERTICAL));
    addConfiguredInput(new ConfiguredInput(ConfiguredInput.Type.axisDigital, AXIS_HORIZONTAL));

    commitConfig();
}

As you see, you must commit the configuration by calling commitConfig().

The different input types

As said before, ControllerMappings support four different controller input types. While ConfiguredInput.Type.button should be clear, difference between axisDigital, axisAnalog and axis is probably not at first glance. Read the JavaDoc for clarification.

Define a default mapping

Override ControllerMappings' getDefaultMapping() method:

@Override
public boolean getDefaultMapping(MappedInputs defaultMapping) {
    // see https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_BUTTON_A
    boolean onAndroid = Gdx.app.getType() == Application.ApplicationType.Android;

    defaultMapping.putMapping(new MappedInput(AXIS_VERTICAL, new ControllerAxis(1)));
    defaultMapping.putMapping(new MappedInput(AXIS_HORIZONTAL, new ControllerAxis(0)));
    defaultMapping.putMapping(new MappedInput(BUTTON_JUMP, new ControllerButton(onAndroid ? 96 : 0)));
    defaultMapping.putMapping(new MappedInput(BUTTON_FIRE, new ControllerButton(onAndroid ? 97 : 1)));
    defaultMapping.putMapping(new MappedInput(BUTTON_START, new ControllerButton(onAndroid ? 108 : 9)));
    defaultMapping.putMapping(new MappedInput(BUTTON_CANCEL, new ControllerButton(onAndroid ? 4 : 8)));

    return true;
}

Let the user record his own mapping

mappings.recordMapping(controller, idToRecord);

returns ControllerMappings.RecordResult: recorded, nothing_done, not_added, need_second_button, not_added_need_button

Don't call on every render(), wait 100ms.

Loading and saving user's recorded mappings

mappings.toJson()
mappings.fillFromJson(jsonValue);

Polling a controller

For polling controllers respecting your mapping, use the MappedController:

    MappedController mappedController = new MappedController(controller, mappings);
    mappedController.isButtonPressed(BUTTON_JUMP);
    mappedController.getAxisValue(AXIS_HORIZONTAL);
    Controllers.addListener(mappedController);

Event based controller input

For event based controller input recpecting your mapping, extend MappedControllerAdapter

Map controller input to keyboard input

In many cases, especially when you do not use an analog axis, a game's controller input will give the player the same actions than keyboard input. You already defined input listeners for keyboard actions, so you just want to map the controller input to keyboard keys. You can use the convinience class ControllerToInputAdapter for this. Exmaple with the NES controller could be:

    controllerToInputAdapter = new ControllerToInputAdapter(controllerMappings);
    controllerToInputAdapter.addButtonMapping(BUTTON_JUMP, Input.Keys.SPACE);
    controllerToInputAdapter.addButtonMapping(BUTTON_FIRE, Input.Keys.ALT);
    controllerToInputAdapter.addButtonMapping(BUTTON_START, Input.Keys.ENTER);
    controllerToInputAdapter.addButtonMapping(BUTTON_CANCEL, Input.Keys.ESCAPE);
    controllerToInputAdapter.addAxisMapping(AXIS_HORIZONTAL, Input.Keys.LEFT, Input.Keys.RIGHT);
    controllerToInputAdapter.addAxisMapping(AXIS_VERTICAL, Input.Keys.UP, Input.Keys.DOWN);
    controllerToInputAdapter.setInputListener(yourKeyboardInputListener);