1.8.4 • Published 5 months ago

phaser3-merged-input v1.8.4

Weekly downloads
1
License
MIT
Repository
github
Last release
5 months ago

Merged input plugin for Phaser 3

A Phaser 3 plugin to map input from keyboard, gamepad & mouse to player actions.

The merged input plugin listens to input from keyboard, connected gamepads and the mouse pointer, updating ‘player’ objects that you may interrogate instead of writing separate input handlers in your game. Each player object contains direction and button actions. These are updated by the corresponding gamepad input, as well as any keys that you assign to the action.

Benefits

. Single place to handle all your input.
. Keyboard, Gamepad & Mouse input is amalgamated.
. Handle input for multiple player objects to easily create multiplayer games.
. Assign and reassign keys to actions for each player, allowing for ‘redefine keys’ function.
. Assign multiple keys to a single action.
. Interrogate current state of all buttons.
. Global events emitted on button down/up.
· (v1.7.0) Plugin specific events for button/keyboard/mouse presses, as well as device changes
. Check for gamepad button presses (i.e. ‘justDown()’ functionality for gamepads)
. Check the last device type used for interaction.
· (v1.4.0) Button mapping to consistent names such as 'RC_X' for the right cluster of buttons
· (v1.4.0) Normalising of gamepad devices, including generating dpad events for gamepads that map them as axis internally
· (v1.8.0) 'ButtonCombos' mimic Phaser's 'KeyCombo' functionality for gamepads.

Installation

npm install phaser3-merged-input

Then you can either add the plugin to Phaser 3's global configuration:

const config = {
    plugins: {
        scene: [
            {
                key: "mergedInput",
                plugin: MergedInput,
                mapping: "mergedInput",
            },
        ],
    }
};

Or using a scene's local configuration:

class InputController extends Phaser.Scene {
    preload() {
        this.load.scenePlugin('mergedInput', MergedInput);
    }

TypeScript

If you're using TypeScript, you will also need to add a class member to the scene so TypeScript knows how to type it.

Example:

class InputController extends Phaser.Scene {
    private mergedInput?: MergedInput;

If you're using the Phaser global config for the plugin, the member name must have the same name as the value the mapping property specified in the Phaser configuration above, or the plugin won't work.

If you're using the scene local plugin, the member name must match the key specified in scenePlugin(key, ...).


Setup

Set up a player object for each player in your game with addPlayer(). Then assign keys to each action with the defineKey() function, e.g.

var player1 = mergedInput.addPlayer(0);
mergedInput.defineKey(0, 'UP', 'W')
    .defineKey(0, 'DOWN', 'S')
    .defineKey(0, 'LEFT', 'A')
    .defineKey(0, 'RIGHT', 'D')
    .defineKey(0, 'B0', 'U')
    .defineKey(0, 'B1', 'I')
    .defineKey(0, 'B2', 'O')
    .defineKey(0, 'B3', 'P')

var player2 = mergedInput.addPlayer(1);
mergedInput.defineKey(1, 'UP', 'UP')
    .defineKey(1, 'DOWN', 'DOWN')
    .defineKey(1, 'LEFT', 'LEFT')
    .defineKey(1, 'RIGHT', 'RIGHT')
    .defineKey(1, 'B0', 'NUMPAD_0')
    .defineKey(1, 'B1', 'NUMPAD_1')
    .defineKey(1, 'B2', 'NUMPAD_2')
    .defineKey(1, 'B3', 'NUMPAD_3')

NEW in v1.4.0

You may now choose to use 'mapped button names' to define keys, instead of button numbers. The plugin will attempt to map each button to the corresponding number, depending on the type of joypad entered. So, instead of using B0, which is the 'A' button on an Xbox controller, but the 'B' button on an 8-bit Do controller, and the 'X' button on a GeeekPi controller, you can now use 'RC_S' for 'Right cluster: South' - for a more consistent approach.

    var player1 = mergedInput.addPlayer(0);
    mergedInput.defineKey(0, 'UP', 'W')
        .defineKey(0, 'DOWN', 'S')
        .defineKey(0, 'LEFT', 'A')
        .defineKey(0, 'RIGHT', 'D')
        .defineKey(0, 'RC_S', 'U')
        .defineKey(0, 'RC_E', 'I')
        .defineKey(0, 'RC_W', 'O')
        .defineKey(0, 'RC_N', 'P')

Then, interrogate your player objects to check for the state of the action, rather than the key, e.g.

    if(player1.direction.DOWN) {
        // Move your player down. This will remain true for as long as the down button is depressed.
    }

    if(player2.buttons.B0 > 0) {
        // Player two is pressing the first button. This will remain true for as long as B0 is depressed.
    }

    if(player1.buttons_mapped.RC_W > 0) {
        // Player one is pressing left button in the right cluster. This will remain true for as long as the button is depressed.
    }

    if(player1.buttons_mapped.START > 0) {
        // Player one is pressing what the plugin considers to be the 'start' button - depending on the controller config.
    }

    if(player1.interaction.device == 'gamepad') {
        // Player one is using a gamepad, you may wish to update your prompts accordingly.
    }

    if (['B8', 'B9', 'B0'].filter(x => player1.interaction.pressed.includes(x)).length) {
        // Player one has just pressed one of the following buttons - B8, B9 or B0.
        // The 'pressed' interaction flag differs from interrogating the buttons directly. It will contain the button(s) pressed for a single update tick, as it happens.
        // Here we're comparing an array of button names to the array of buttons pressed in the step.
    }

    // NEW in v1.6.0
    if (player1.interaction.isPressed(['RC_S', 'LC_E'])) {
        // Player one has just pressed one of the following buttons - Right cluster: South or Left cluster (DPad): East.
        // Instead of comparing arrays directly as above, we're using the included helper function here, which will return any matching buttons that were pressed in this update step.
    }

New in v1.7.0

A new plugin specific eventEmitter instance exists at mergedInput.events. You may use this across your game to listen for keypresses, button presses and device changes (i.e. moving from using the keyboard to a gamepad).

New in v1.8.0

BUTTON COMBOS ARE HERE!!
A new 'ButtonCombo' exists in the merged input plugin to mimic Phaser's native KeyCombos for gamepad/player combinations.
Button combos emit buttoncombomatch events.
Setting them up is easy:

    let combos_konami = mergedInput.createButtonCombo(player1, ['UP', 'UP', 'DOWN', 'DOWN', 'LEFT', 'RIGHT', 'LEFT', 'RIGHT', 'RC_E', 'RC_S'], { resetOnMatch: true });
    combos_konami.name = 'Konami Code';

    mergedInput.events.on('buttoncombomatch', event => {
        console.log(`Player: ${event.player.index} entered: ${event.combo.name}!`);
    });

Note that combo checking only occurrs on gamepad actions. Keyboard combos are still handled by Phaser.

Demo / Dev

A demo scene is included in the repository.
The demo has been updated to incorporate the mapped buttons and interactions included in v1.4.0 and the helper functions added in v1.6.0

npm.io

Install with npm install, then use npm run dev to spin up a development server and run the demo scene.

Build plugin

Build the plugin including minified version. Targets the dist folder. npm run build

Changelog

v1.8.4 - 2023-11-26 Bugfix: Mouse pointer checkDown function timers were handled incorrrectly.

v1.8.3 - 2023-11-18
Bugfix: When using a joypad that maps direction buttons to the left axis, the fake DPad functionality was not mimicking button number value changes for buttons and buttons_mapped.

v1.8.2 - 2023-11-13
Bugfix: Gamepad button release was not freeing the timer's tick var.

v1.8.1 - 2023-10-29
Added mouse pointers to checkDown function.
Fixed issue with generic player helper functions when player not fully initialised.

v1.8.0 - 2023-10-29
Added new ButtonCombos, to mimic Phaser's KeyCombos with gamepad buttons.
Added timers to button presses, we're now able to retrieve a pressed, released, and duration value.
Added extra helper functions to the player object, including isDown and checkDown to mimic Phaser's keyboard handling with merged input.
Player helper objects are now able to be called directly on the player object and will accept either mapped or unmapped button actions.

v1.7.0 - 2023-10-15 Added a new plugin specific instance of the event emitter. The old 'mergedInput' events continue to fire on the scene's emitter; however as they are all the same event with extra data, you need to listen to all every 'mergedInput' event and filter for the ones you need. The new plugin specific instance allows you to listen only to the events you need.

v1.6.1 - 2023-06-01
Updated pointer events to only be set when adding the first player. Pointer events now check for player object. Updated typings With many thanks to @Dan-Mizu for help with this release.

v1.6.0 - 2022-12-05
Improved handling of the 'pressed' and 'released' events. Previously it was possible to miss a press event if two happened within the same update step.
IMPORTANT: The pressed & released properties under the player's interaction object has changed from a string to an array, to allow for multiple values in an update step.
Any code that checks these properties should be updated to expect an array of one or more values. New helper functions isPressed() and isReleased() have been added to the interaction and interaction_mapped properties of the player object. Use these to check if one or more buttons were pressed/released in the current update step. See the demo for more details.

v1.5.0 - 2022-08-22
When the game loses focus, the plugin will now reset each of the defined keys to avoid them getting stuck when returning to the game.

v1.4.0 - 2022-07-03
Added normalisation of gamepad devices, using mapping files located in the new configs folder.
Added friendly mapped button names, and a new batch of properties under interaction_mapped and buttons_mapped.
Added fake DPad functionality to better handle joypads that map their DPads to the left axis, instead of the standard buttons 12-15.
Added a debug scene to the demo.

v1.3.1 - 2022-03-11
Fixed missing code caused by bad merge!
Added keywords
Clean up readme.md

v1.3.0 - 2022-03-10
Migrated keyboard interaction flags from the justDown and justUp key functions, to instead use the keyboard's keyDown and keyUp events.
This way we maintain consistancy between keyboard and gamepad interactions, as events trigger before the scene's update call.
Added a new released key to the interaction object to indicate when a button has been released.
Added a new lastPressed and lastReleased key, to replace the existing pressed key - the old pressed key remains for backwards compatability.
Added TypeScript support.
With many thanks to @zewa666 and @bbugh for help with this release.

v1.2.8 - 2021-07-23
Added gamepad directions to interaction buffer/presses to match keyboard interactions.

v1.2.7 - 2021-07-06
Changed the order of buffer/pressed checking in update loop.

v1.2.6 - 2021-05-04
Guess who forgot to build again??

v1.2.5 - 2021-05-04
Updated buttondown and buttonup event listeners from per pad, to per input system. It seems the per pad listeners weren't firing for pad 2 and this method works around the problem. Also added an addPlayer call if the corresponding player is missing. Updated phaser dependancy

v1.2.4 - 2020-05-08
And again, remembering to include the built files would be a bonus.

v1.2.3 - 2020-05-08
Added extra handling for 'null' gamepads.

v1.2.2 - 2020-05-03
Added secondary direction key detection, so that secondary directions may be instigated through a keypress as well as the right stick of a gamepad. Added timestamps to interactions making it possible to tell which was last used, e.g. keyboard vs mouse.

v1.2.1 - 2020-04-27
Actually added the build files.

v1.2.0 - 2020-04-27
You are now able to pass a player's X/Y position to a player object, whereupon the position of the mouse in relation to that player will be used to determine mouse bearings and degrees

v1.1.0 - 2020-04-19
Plugin now handles secondary directional movement from the second stick on a gamepad. Bearings and degrees have been added to direction objects.

Credits

Written by Gary Stanton
Built from the Plugin Starter Kit by Niklas Berg
Demo sprites by Nicolae Berbece


Functions

addPlayer()

Add a new player object to the players array

ParamType
indexnumber

getPlayer(index)

Get player object

ParamType
thisPlayernumber

defineKey(player, action, value, append)

Define a key for a player/action combination | Param | Type | | | --- | --- | --- | | player | number | The player ID on which we're defining a key | | action | string | The action to define | | value | string | The key to use | | append | boolean | When true, this key definition will be appended to the existing key(s) for this action |

createButtonCombo(player, buttons, config)

A ButtonCombo will listen for a specific combination of buttons from the given player's gamepad, and when it receives them it will emit a buttoncombomatch event.

ParamType
playerobjectThe player object on which we're defining a key
buttonsarrayAn array of buttons to act as the combo. You may use directions 'UP', button IDs 'B12' or mapped buttons 'LC_N'
configPhaser.Types.Input.Keyboard.KeyComboConfigA Key Combo configuration object. Uses the same config as Phaser's native KeyCombo classes

{player}.isPressed(button)

Check if button(s) were pressed during an update tick

ParamType
buttonstring/array

{player}.isReleased(button)

Check if button(s) were released during an update tick

ParamType
buttonstring/array

{player}.isDown(button)

Check if button(s) were held down during an update tick

ParamType
buttonstring/array

{player}.checkDown(button)

Check if button(s) were held down during an update tick
You may provide a duration to this method and it will return true every X milliseconds.

ParamType
buttonstring/array
durationnumberThe duration which must have elapsed before this button is considered as being down.
includeFirstbooleanWhen true, include the first press of a button, otherwise wait for the first passing of the duration.

Events

EventDescriptionData
gamepad_connectedGamepad is connectedgamepad instance
device_changedThe last input device has changedlast device used (keyboard/gamepad/mouse)
keyboard_keydownKeyboard key pressedplayer: player instance, key: keycode pressed
keyboard_keyupKeyboard key releasedplayer: player instance, key: keycode pressed
gamepad_buttondownGamepad button pressedplayer: player instance, button: button number pressed
gamepad_buttonupGamepad button releasedplayer: player instance, button: button number released
gamepad_directiondownGamepad D-Pad pressedplayer: player instance, direction: D-Pad direction pressed
gamepad_directionupGamepad D-Pad releasedplayer: player instance, direction: D-Pad direction released
gamepad_directionupGamepad D-Pad releasedplayer: player instance, direction: D-Pad direction released
pointer_downMouse button pressedbutton number pressed
pointer_upMouse button releasedbutton number released
buttoncombomatchA button combo match has occurredplayer: player instance, combo: The ButtonCombo object that matched
1.8.2

6 months ago

1.8.1

6 months ago

1.8.0

6 months ago

1.7.0

7 months ago

1.8.4

5 months ago

1.8.3

6 months ago

1.6.1

11 months ago

1.6.0

1 year ago

1.5.0

2 years ago

1.4.0

2 years ago

1.3.1

2 years ago

1.3.0

2 years ago

1.2.8

3 years ago

1.2.7

3 years ago

1.2.6

3 years ago

1.2.5

3 years ago

1.2.4

4 years ago

1.2.3

4 years ago

1.2.2

4 years ago

1.2.1

4 years ago

1.2.0

4 years ago

1.1.1

4 years ago

1.0.2

5 years ago

1.0.1

5 years ago

1.0.0

5 years ago