# Gamepad Controller

**URL:** <https://forum.babylonjs.com/t/gamepad-controller/34409>\
**Category:** Questions\
**Tags:** arcrotatecamera, gamepad, arcrotatecamerainput, arcrotatecameragamep\
**Created:** [October 2, 2022, 9:06pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409 "2022-10-02T21:06:15Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![arcman7](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/arcman7/32/20249_2.png) [@arcman7](https://forum.babylonjs.com/u/arcman7)\
**Post date:** [October 2, 2022, 9:06pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/1 "2022-10-02T21:06:15Z")

</div>

Hey yall,

I looking for more documentation or examples regarding the classes:

```auto
{ 
  GamepadManager, Gamepad, ,Xbox360Pad, 
  DualShockPad, GenericPad, PoseEnabledController, ArcRotateCamera, 
  ArcRotateCameraGamepadInput, ArcRotateCameraInputsManager,
} 

```

But I’m not really finding much other than these two pages

> **[ArcRotateCameraGamepadInput | Babylon.js Documentation](https://doc.babylonjs.com/typedoc/classes/BABYLON.ArcRotateCameraGamepadInput#camera)**
>
> Manage the gamepad inputs to control an arc rotate camera. \[API\]

> **[ArcRotateCameraInputsManager | Babylon.js Documentation](https://doc.babylonjs.com/typedoc/classes/BABYLON.ArcRotateCameraInputsManager)**
>
> Default Inputs manager for the ArcRotateCamera.It groups all the default supported inputs for ease of use. \[API\]

I want to have my character and it’s ArcRotateCamera be controlled by a gamepad class. I can set this up using my own event handlers and what not, but it seems like there is a way to do this through babylon.js - but I’m not sure how.

---

<div class="post-metadata">

**Author:** ![sebavan](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/sebavan/32/57_2.png) [@sebavan](https://forum.babylonjs.com/u/sebavan)\
**Post date:** [October 3, 2022, 12:55pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/2 "2022-10-03T12:55:26Z")

</div>

Adding our input Guru @PolygonalSun and @PirateJC as it seems like there is room to improve the Doc in this area.

---

<div class="post-metadata">

**Author:** ![Takemura](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/takemura/32/25836_2.png) [@Takemura](https://forum.babylonjs.com/u/Takemura)\
**Post date:** [October 3, 2022, 1:16pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/3 "2022-10-03T13:16:31Z")

</div>

Is this kinda what you looking for?

```auto
const gamepadManager = new BABYLON.GamepadManager();
    gamepadManager.onGamepadConnectedObservable.add((gamepad, state) => {
        gamepad.onleftstickchanged((values) => {
            console.log(values.x+" "+values.y)
        });

        camera.inputs.add(new BABYLON.ArcRotateCameraGamepadInput());
        camera.inputs.attached.gamepad.gamepadAngularSensibility = 250;
        camera.inputs.addGamepad();
    });

```

---

<div class="post-metadata">

**Author:** ![arcman7](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/arcman7/32/20249_2.png) [@arcman7](https://forum.babylonjs.com/u/arcman7)\
**Post date:** [October 3, 2022, 5:50pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/4 "2022-10-03T17:50:39Z")

</div>

Yeah more or less-

> **[Babylon.js Playground](https://playground.babylonjs.com/#CTCSWQ%23945)**
>
> Babylon.js playground is a live editor for Babylon.js WebGL 3D scenes

This example ^ has the behavior I’m looking for.

I’ve implemented something seems to work for now, but it feels hacky:

```auto
/* ControllerPlugin.ts */
export type XBOX_BUTTON = 0 | 1 | 2 | 3 | 10
const A: XBOX_BUTTON = 0
const B: XBOX_BUTTON = 1
const X: XBOX_BUTTON = 2
const Y: XBOX_BUTTON = 3
const DASH: XBOX_BUTTON = 10
export const XBOX_BUTTONS = { A, B, X, Y, DASH }

export const leftStick = { x: 0, y: 0 }
export const rightStick = { x: 0, y: 0 }

function setupXboxController(gamepad: Gamepad) {
    if (!(gamepad instanceof Xbox360Pad)) return
    gamepad.onButtonDownObservable.add((button, _state)=>{
      console.log('xbox controller button pressed: ', button)
      switch(button) {
        case XBOX_BUTTONS.A:
          this._playerInput._jumpCallback()
          break
        case XBOX_BUTTONS.B:
          break
        case XBOX_BUTTONS.X:
          this._playerInput._onRightClickCallback()
          break
        case XBOX_BUTTONS.Y:
          this._playerInput._inventoryToggleCallback()
          break
        case XBOX_BUTTONS.DASH:
          console.log('dashing!')
          this._playerInput.dashing = true
          break
        default:
          console.warn('pressed unknown button: ', button)
          break
      }

    })
    gamepad.onButtonUpObservable.add((button, _state) => {
      console.log('xbox controller button released: ', button)
      switch(button) {
        case XBOX_BUTTONS.DASH:
          console.log('stop dashing!')
          this._playerInput.dashing = false
          break
        default:
          console.warn('released unknown button: ', button)
          break
      }
    })

    /* Stick events */
    gamepad.onleftstickchanged((values) => {
      /* Account for dead-zone */
      leftStick.x = Math.abs(values.x) > 0.05 ? values.x : 0
      leftStick.y = Math.abs(values.y) > 0.05 ? values.y : 0
    })
    gamepad.onrightstickchanged((values) => {
      /* Account for dead-zone */
      rightStick.x = Math.abs(values.x) > 0.05 ? values.x : 0
      rightStick.y = Math.abs(values.y) > 0.05 ? values.y : 0
    })
  }

```

And then in my player model file:

```auto
/* Player.ts */
const rightAxis = new Vector3(1, 0, 0)

function updateFromGamepadControls(): void {
    const cameraForwardRayPosition = this.camera.getForwardRay().direction
    const cameraRight = this.camera.getDirection(rightAxis).scaleInPlace(leftStick.x)

    this._moveDirection = cameraForwardRayPosition.scale(
      -leftStick.y
    ).addInPlace(cameraRight)

    this._moveDirection.y = 0

    if (playerInput.dashing) {
      this.speed = this.runSpeed
    } else {
      this.speed = this.walkSpeed 
    }
}

```

If I don’t do this in this way, and instead attach the gamepad input directly to the camera via `camera.inputs.addGamepad()` then the left stick will control the zoom radius of the ArcRotateCamera, which I don’t want.

---

<div class="post-metadata">

**Author:** ![Takemura](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/takemura/32/25836_2.png) [@Takemura](https://forum.babylonjs.com/u/Takemura)\
**Post date:** [October 3, 2022, 6:24pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/5 "2022-10-03T18:24:24Z")

</div>

To change leftstick-behaviour you can customize camera inputs, see docs and babylonjs code:

> **[Customizing Camera Inputs | Babylon.js Documentation](https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs)**
>
> Learn how to customize input controls for Babylon.js cameras.

> <https://github.com/BabylonJS/Babylon.js/blob/master/packages/dev/core/src/Cameras/Inputs/arcRotateCameraGamepadInput.ts>

Regarding non-smooth feeling, maybe a slowed stabilistation similiar to this can help:

> <https://github.com/xtt13/Antimatter/blob/master/src/controlls/InputManager.js>

---

<div class="post-metadata">

**Author:** ![carolhmj](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/carolhmj/32/25918_2.png) [@carolhmj](https://forum.babylonjs.com/u/carolhmj)\
**Post date:** [November 3, 2022, 2:16pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/6 "2022-11-03T14:16:38Z")

</div>

Hi @arcman7 just checking in if you need any more help?

---

<div class="post-metadata">

**Author:** ![arcman7](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/arcman7/32/20249_2.png) [@arcman7](https://forum.babylonjs.com/u/arcman7)\
**Post date:** [November 3, 2022, 8:33pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/7 "2022-11-03T20:33:37Z")

</div>

Not as of yet, but thank you for checking in! I have an initial implementation working atm based on what’s been posted so far.

---

<div class="post-metadata">

**Author:** ![Josip\_Almasi](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/josip_almasi/32/6391_2.png) [@Josip\_Almasi](https://forum.babylonjs.com/u/Josip_Almasi)\
**Post date:** [December 30, 2023, 12:57pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/8 "2023-12-30T12:57:57Z")

</div>

Works for me - until I switch the camera. After that, gamepad doesn’t work with ArcRotateCamera any longer, no matter what.  
I’m switching between 1st and 3rd person camera, Universal/ArcRotate, like scene.activeCamera = camera, camera.attachControl(). Everything works fine, except the gamepad input of ArcRotateCamera never takes.  
Seems that one special case it works is when gamepad is attached while ArcRotateCamera is active camera.  
Looks like bug in attachControl(). Or, is there some additional bookkeeping needed?

---

<div class="post-metadata">

**Author:** ![arcman7](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/arcman7/32/20249_2.png) [@arcman7](https://forum.babylonjs.com/u/arcman7)\
**Post date:** [December 31, 2023, 1:17am UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/9 "2023-12-31T01:17:49Z")

</div>

I think I noticed that as well a while back, but I haven’t been using the controller that I built lately. I may have ended up just keeping a separate camera on hand for each control type in use.

---

<div class="post-metadata">

**Author:** ![Josip\_Almasi](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/josip_almasi/32/6391_2.png) [@Josip\_Almasi](https://forum.babylonjs.com/u/Josip_Almasi)\
**Post date:** [January 1, 2024, 3:03pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/10 "2024-01-01T15:03:43Z")

</div>

It’s a bug alright.  
I’ve compared attachControl() methods of FreeCameraGamepadInput and ArcRotateCameraGamepadInput, and this is this is missing for arc rotate camera:

```auto
        // if no xbox controller was found, but there are gamepad controllers, take the first one
        if (!this.gamepad && manager.gamepads.length) {
            this.gamepad = manager.gamepads[0];
        }

```

Filed the bug here: [ArcRotateCamera gamepad input other than XBOX](https://forum.babylonjs.com/t/arcrotatecamera-gamepad-input-other-than-xbox/46859)  
Works for me with this workaround:

```auto
    const gamepadManager = this.scene.gamepadManager;
    this.gamepadInput = new BABYLON.ArcRotateCameraGamepadInput();
    const oldAttach = this.gamepadInput.attachControl;
    this.gamepadInput.attachControl = () => {
      oldAttach;
      if (!this.gamepadInput.gamepad && gamepadManager.gamepads.length ) {
        this.gamepadInput.gamepad = gamepadManager.gamepads[0];
      }
    }

```

Regarding to the original code, note that we don’t need to create new GamepadManager, Scene already contains one.

---

<div class="post-metadata">

**Author:** ![sebavan](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/sebavan/32/57_2.png) [@sebavan](https://forum.babylonjs.com/u/sebavan)\
**Post date:** [January 2, 2024, 10:10pm UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/11 "2024-01-02T22:10:31Z")

</div>

will be fixed by [Fix arcrotate gamepad input by sebavan · Pull Request #14665 · BabylonJS/Babylon.js · GitHub](https://github.com/BabylonJS/Babylon.js/pull/14665)

---

<div class="post-metadata">

**Author:** ![Josip\_Almasi](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/josip_almasi/32/6391_2.png) [@Josip\_Almasi](https://forum.babylonjs.com/u/Josip_Almasi)\
**Post date:** [January 3, 2024, 9:59am UTC](https://forum.babylonjs.com/t/gamepad-controller/34409/12 "2024-01-03T09:59:03Z")

</div>

Thanks for the quick fix!
