Configure keyboard inputs once for all scenes to use

Edit: Aww, @samme beat me to it again :sweat_smile:

This post made me think a lot about WHY Phaser doesn’t provide a global keyboardPlugin in favor of scene-specific keyboardPlugin instances, and I believe it has to do with handling event propagation. Much like how click events “bubble up” in javascript when DOM elements are layered on top of each other, Phaser’s approach provides a lot of methods that give you control over how input events propagate through scenes in the scene list, all the way to the global event listener. For a little clarity, I’d suggest reading this dev log, reading rex’s notes on keyboard events, and fiddling with this example of events propagating across scenes.

This all might be a bit overkill for your game though, and it’s a classic case of sacrificing simplicity for tighter control. I think your primary concern is code maintainability - you want your inputs to be defined just once so you only have to change them in one place, both for your own purposes and if your players want to customize their controls. So with that in mind, here’s what I’m thinking:

  1. Create new key objects for each scene, but abstract the actual keys used. This gives you the full power of event propagation between scenes, but gives you the freedom to change your key codes in one place. In this way you’ve dissociated your naming that you’ll use in your scene’s logic (update function, events, etc) from the actual keys used.
// in a global object variable, or in a separate file that you import into each scene
const { KeyCodes } = Phaser.Input.Keyboard; 
const KEY_BINDINGS = {
  JUMP:   KeyCodes.SPACE,
  ATTACK: KeyCodes.A,
};

// in one of your scenes
create() {
  const KEYS = this.input.keyboard.addKeys(KEY_BINDINGS);
}

update() {
  if (KEYS.JUMP.isDown) // Do jumpy stuff
}
  1. Do what other people have suggested and create one set of controls in a scene that persists throughout your game and runs in parallel to your other scenes. You can access the key objects from this scene in your other scenes, and you can use whatever method you want to make them globally accessible. While this seems simpler in theory, since your key objects only exist in one place and you’re just accessing the same references from different scenes, I don’t think I like it as much - you can’t take advantage of Phaser’s scene propagation methods, and it make your scene classes just a little less modular and independent.
// Scene A  (with key "sceneA")
create() {
  const { KeyCodes } = Phaser.Input.Keyboard; 
  this.KEYS = this.input.keyboard.addKeys({
    JUMP:   KeyCodes.SPACE,
    ATTACK: KeyCodes.A,
  });
}

// Scene B  (with key "sceneB")
create() {
  this.KEYS = this.scene.get("sceneA").KEYS;
}

update() {
  const { KEYS } = this;
  if (KEYS.JUMP.isDown) // Do jumpy stuff
}

In the end though, it’s entirely up to you! Phaser is just javascript, and it has full access to anything you’d normally do in the browser - so you could use your original game controls code of adding event listeners to the window and using a global object to track their up/down states, and refer to these in the update methods of your scenes. Then you could change this later if you feel it’s necessary as you get more comfortable with the framework.

I’d suggest trying out the events system though, it’s no less performant, and although it seems more obtuse, it gives you a lot of freedom and can make your code very modular and succinct! You may even be inspired to emit your own custom events to communicate between scenes or even between game objects as you get more comfortable with it!

1 Like