• Public
  • Public/Protected
  • All

Class Gamepads

Excalibur leverages the HTML5 Gamepad API where it is supported to provide controller support for your games.

You can query any Gamepads that are connected or listen to events ("button" and "axis").

You must opt-in to controller support (Gamepads.enabled) because it is a polling-based API, so we have to check it each update frame. If an gamepad related event handler is set, you will automatically opt-in to controller polling.

HTML5 Gamepad API only supports a maximum of 4 gamepads. You can access them using the Gamepads.at method. If a Gamepad is not connected, it will simply not throw events.

Gamepad Filtering

Different browsers/devices are sometimes loose about the devices they consider Gamepads, you can set minimum device requirements with engine.input.gamepads.setMinimumGamepadConfiguration so that undesired devices are not reported to you (Touchpads, Mice, Web Cameras, etc.).

// ensures that only gamepads with at least 4 axis and 8 buttons are reported for events
   axis: 4,
   buttons: 8


You can subscribe to gamepad connect and disconnect events through engine.input.gamepads.on.

A GamepadConnectEvent or GamepadDisconnectEvent will be passed to you.

  • connect - When a gamepad connects it will fire this event and pass a GamepadConnectEvent with a reference to the gamepad.
  • disconnect - When a gamepad disconnects it will fire this event and pass a GamepadDisconnectEvent

Once you have a reference to a gamepad you may listen to changes on that gamepad with .on. A GamepadButtonEvent or GamepadAxisEvent will be passed to you.

  • button - Whenever a button is pressed on the game
  • axis - Whenever an axis

engine.input.gamepads.on('connect', (ce: ex.Input.GamepadConnectEvent) => {
   var newPlayer = CreateNewPlayer(); // pseudo-code for new player logic on gamepad connection
   console.log("Gamepad connected", ce);
   ce.gamepad.on('button', (be: ex.GamepadButtonEvent) => {
      if(be.button === ex.Input.Buttons.Face1) {

   ce.gamepad.on('axis', (ae: ex.GamepadAxisEvent) => {
     if(ae.axis === ex.Input.Axis.LeftStickX && ae.value > .5){

Responding to button input

Gamepad buttons typically have values between 0 and 1, however depending on the sensitivity of the controller, even if a button is idle it could have a very tiny value. For this reason, you can pass in a threshold to several methods to customize how sensitive you want to be in detecting button presses.

You can inspect any connected Gamepad using Gamepad.isButtonPressed, Gamepad.getButton, or you can subscribe to the button event published on the Gamepad which passes a GamepadButtonEvent to your handler.

// enable gamepad support
engine.input.gamepads.enabled = true;
// query gamepad on update
engine.on("update", function (ev) {
  // access any gamepad by index
  if (engine.input.gamepads.at(0).isButtonPressed(ex.Input.Buttons.Face1)) {
    ex.Logger.getInstance().info("Controller A button pressed");
  // query individual button
  if (engine.input.gamepads.at(0).getButton(ex.Input.Buttons.DpadLeft) > 0.2) {
    ex.Logger.getInstance().info("Controller D-pad left value is > 0.2")
// subscribe to button events
engine.input.gamepads.at(0).on("button", function (ev) {
  ex.Logger.getInstance().info(ev.button, ev.value);

Responding to axis input

Gamepad axes typically have values between -1 and 1, but even idle sticks can still propogate very small values depending on the quality and age of a controller. For this reason, you can set Gamepads.MinAxisMoveThreshold to set the (absolute) threshold after which Excalibur will start publishing axis events. By default it is set to a value that normally will not throw events if a stick is idle. You can query axes via Gamepad.getAxes or by subscribing to the axis event on Gamepad which passes a GamepadAxisEvent to your handler.

// enable gamepad support
engine.input.gamepads.enabled = true;
// query gamepad on update
engine.on("update", function (ev) {
  // access any gamepad by index
  var axisValue;
  if ((axisValue = engine.input.gamepads.at(0).getAxes(ex.Input.Axes.LeftStickX)) > 0.5) {
    ex.Logger.getInstance().info("Move right", axisValue);
// subscribe to axis events
engine.input.gamepads.at(0).on("axis", function (ev) {
  ex.Logger.getInstance().info(ev.axis, ev.value);







Private _engine

_engine: Engine

Private _gamePadTimeStamps

_gamePadTimeStamps: Array<number> = [0, 0, 0, 0]

Private _initSuccess

_initSuccess: boolean = false

Private _minimumConfiguration

_minimumConfiguration: IGamepadConfiguration = null

Private _navigator

_navigator: INavigatorGamepads = <any>navigator

Private _oldPads

_oldPads: Gamepad[] = []

Private _pads

_pads: Gamepad[] = []


enabled: boolean = false

Whether or not to poll for Gamepad input (default: false)


eventDispatcher: EventDispatcher

Direct access to the game object event dispatcher.


supported: boolean = !!(<any>navigator).getGamepads

Whether or not Gamepad API is supported

Static MinAxisMoveThreshold

MinAxisMoveThreshold: number = 0.05

The minimum value an axis has to move before considering it a change


Private _clonePad

  • Fastest way to clone a known object is to do it yourself


    Returns Gamepad

Private _clonePads

Private _enableAndUpdate

  • _enableAndUpdate(): void
  • When implicitly enabled, set the enabled flag and run an update so information is updated

    Returns void

Private _isGamepadValid

  • Checks a navigator gamepad against the minimum configuration if present.


    Returns boolean


  • Safely retrieves a Gamepad at a specific index and creates one if it doesn't yet exist


    • index: number

    Returns Gamepad


  • count(): number
  • Gets the number of connected gamepads

    Returns number


  • emit(eventName: string, eventObject?: GameEvent): void
  • Emits a new event


    • eventName: string

      Name of the event to emit

    • Optional eventObject: GameEvent

      Data associated with this event

    Returns void


  • Returns a list of all valid gamepads that meet the minimum configuration requirement.

    Returns Gamepad[]


  • init(): void
  • Returns void


  • off(eventName: string, handler?: function): void
  • Parameters

    • eventName: string
    • Optional handler: function

    Returns void


  • on(eventName: connect, handler: function): any
  • on(eventName: disconnect, handler: function): any
  • on(eventName: button, handler: function): any
  • on(eventName: axis, handler: function): any
  • on(eventName: string, handler: function): any


  • Sets the minimum gamepad configuration, for example {axis: 4, buttons: 4} means this game requires at minimum 4 axis inputs and 4 buttons, this is not restrictive all other controllers with more axis or buttons are valid as well. If no minimum configuration is set all pads are valid.


    Returns void


  • update(delta: number): void
  • Updates Gamepad state and publishes Gamepad events


    • delta: number

    Returns void

Static extend

  • extend(methods: any): any
  • You may wish to extend native Excalibur functionality in vanilla Javascript. Any method on a class inheriting Class may be extended to support additional functionality. In the example below we create a new type called MyActor.

    var MyActor = Actor.extend({
       constructor: function() {
          this.newprop = 'something';
          Actor.apply(this, arguments);
       update: function(engine, delta) {
          // Implement custom update
          // Call super constructor update
          Actor.prototype.update.call(this, engine, delta);
          console.log("Something cool!");
    var myActor = new MyActor(100, 100, 100, 100, Color.Azure);

    In TypeScript, you only need to use the extends syntax, you do not need to use this method of extension.


    • methods: any

      A JSON object contain any methods/properties you want to extend

    Returns any