Controles, gamepads y joysticks

Godot admite cientos de modelos de controles gracias a la comunidad SDL game controller database.

Los controles son compatibles con Windows, macOS, Linux, Android, iOS y HTML5.

Tenga en cuenta que los dispositivos más especializados como volantes, pedales de timón y HOTAS están menos probados y es posible que no siempre funcionen como se esperaba. Si tiene acceso a uno de esos dispositivos, no dude en informar errores en GitHub.

En esta guía aprenderás:

  • Cómo escribir su lógica de entrada para admitir entradas de teclado y de controles.

  • Cómo los controles pueden comportarse de manera diferente a la entrada del teclado/mouse.

  • Solución de problemas con los controles en Godot.

Soporte para entrada universal

Gracias al sistema de acción de entrada de Godot, hace posible admitir la entrada tanto del teclado como del control sin tener que escribir rutas de código separadas. En lugar de codificar las teclas o los botones del control en sus scripts, debe crear acciones de entrada en la Configuración del Proyecto, que luego se referirán a las entradas de clave y control especificadas.

Las acciones de entrada se explican en detalle en la página Usando InputEvent.

Nota

A diferencia de la entrada del teclado, admitir la entrada del mouse y del control para una acción (como mirar alrededor en un juego en primera persona) requerirá diferentes rutas de código, ya que deben manejarse por separado.

¿Qué método de entrada singleton debo usar?

Hay 3 formas de obtener entrada de forma analógica:

  • Cuando tenga dos ejes (como un joystick o movimiento WASD) y desee que ambos ejes se comporten como una sola entrada, use Input.get_vector():

# `velocity` will be a Vector2 between `Vector2(-1.0, -1.0)` and `Vector2(1.0, 1.0)`.
# This handles deadzone in a correct way for most use cases.
# The resulting deadzone will have a circular shape as it generally should.
var velocity = Input.get_vector("move_left", "move_right", "move_forward", "move_back")

# The line below is similar to `get_vector()`, except that it handles
# the deadzone in a less optimal way. The resulting deadzone will have
# a square-ish shape when it should ideally have a circular shape.
var velocity = Vector2(Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
            Input.get_action_strength("move_back") - Input.get_action_strength("move_forward")).clamped(1)
// `velocity` will be a Vector2 between `Vector2(-1.0, -1.0)` and `Vector2(1.0, 1.0)`.
// This handles deadzone in a correct way for most use cases.
// The resulting deadzone will have a circular shape as it generally should.
Vector2 velocity = Input.GetVector("move_left", "move_right", "move_forward", "move_back");

// The line below is similar to `get_vector()`, except that it handles
// the deadzone in a less optimal way. The resulting deadzone will have
// a square-ish shape when it should ideally have a circular shape.
Vector2 velocity = new Vector2(Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"),
            Input.GetActionStrength("move_back") - Input.GetActionStrength("move_forward")).Clamped(1);
  • Cuando tiene un eje que puede ir en ambos sentidos (como un acelerador en una palanca de vuelo), o cuando desea manejar ejes separados individualmente, use Input.get_axis():

# `walk` will be a floating-point number between `-1.0` and `1.0`.
var walk = Input.get_axis("move_left", "move_right")

# The line above is a shorter form of:
var walk = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
// `walk` will be a floating-point number between `-1.0` and `1.0`.
float walk = Input.GetAxis("move_left", "move_right");

// The line above is a shorter form of:
float walk = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left");
  • Para otros tipos de entrada analógica, como manejar un disparador o manejar una dirección a la vez, use Input.get_action_strength():

# `strength` will be a floating-point number between `0.0` and `1.0`.
var strength = Input.get_action_strength("accelerate")
// `strength` will be a floating-point number between `0.0` and `1.0`.
float strength = Input.GetActionStrength("accelerate");

Para entradas digitales/booleanas no analógicas (sólo valores "presionados" o "no presionados"), como botones del control, botones del mouse o teclas del teclado, use Input.is_action_pressed():

# `jumping` will be a boolean with a value of `true` or `false`.
var jumping = Input.is_action_pressed("jump")
// `jumping` will be a boolean with a value of `true` or `false`.
bool jumping = Input.IsActionPressed("jump");

En las versiones de Godot anteriores a 3.4, como 3.3, Input.get_vector() y Input.get_axis() no están disponibles. Sólo Input.get_action_strength() y Input.is_action_pressed() están disponibles en Godot 3.3.

Diferencias entre teclado/mouse y entrada del controlador

Si está acostumbrado a manejar la entrada del teclado y el mouse, es posible que se sorprenda de cómo los controles manejan situaciones específicas.

Zona muerta

A diferencia de los teclados y ratones, los controles ofrecen ejes con entradas analógicas. La ventaja de las entradas analógicas es que ofrecen flexibilidad adicional para las acciones. A diferencia de las entradas digitales que sólo pueden proporcionar potencias de 0.0 y 1.0, una entrada analógica puede proporcionar cualquier intensidad entre 0.0 y 1.0. La desventaja es que sin un sistema de zona muerta, la fuerza de un eje analógico nunca será igual a 0.0 debido a cómo está construido físicamente el control. En cambio, permanecerá en un valor bajo como 0.062. Este fenómeno se conoce como drifting y puede ser más notorio en controles viejos o defectuosos.

Tomemos un juego de carreras como ejemplo del mundo real. Gracias a las entradas analógicas, podemos conducir el coche lentamente en una dirección u otra. Sin embargo, sin un sistema de zona muerta, el automóvil se conduciría lentamente por sí mismo incluso si el jugador no está tocando el joystick. Esto se debe a que la fuerza del eje direccional no será igual a 0.0 cuando lo esperamos. Como no queremos que nuestro coche se dirija sólo en este caso, definimos un valor de "zona muerta" de 0.2 que ignorará todas las entradas cuya fuerza sea inferior a 0.2. Un valor de zona muerta ideal es lo suficientemente alto como para ignorar la entrada causada por la deriva del joystick, pero es lo suficientemente bajo como para no ignorar la entrada real del jugador.

Godot cuenta con un sistema de zona muerta incorporado para abordar este problema. El valor predeterminado es 0.2, pero puede aumentarlo o disminuirlo por acción en la pestaña Mapa de entrada de Configuración del proyecto. Para Input.get_vector(), se puede especificar la zona muerta o, de lo contrario, se calculará el valor medio de la zona muerta de todas las acciones del vector.

Eventos de "eco"

A diferencia de la entrada de teclado, mantener presionado un botón del control, como la dirección del D-pad, no generará eventos de entrada repetidos a intervalos fijos (también conocidos como eventos de "eco"). Esto se debe a que, en primer lugar, el sistema operativo nunca envía eventos de "eco" para la entrada del control.

Si desea que los botones del control envíen eventos de eco, tendrá que generar InputEvent objetos por código y analizarlo usando Input.parse_input_event() en intervalos regulares. Esto se puede lograr con la ayuda de un nodo Timer.

Solución De Problemas

Ver también

You can view a list of known issues with controller support on GitHub.

Mi control no es reconocido por Godot.

Primero, revisa que tu control es detectado por otras aplicaciones. Puedes usar el sitio web Gamepad Tester para confirmar que tu control es detectado.

Mi control tiene botones o ejes asignados incorrectamente.

Si los botones se asignan incorrectamente, esto puede deberse a una asignación errónea del SDL game controller database. Puede contribuir con un mapeo actualizado para que se incluya en la próxima versión de Godot abriendo un pull request en el repositorio vinculado.

Hay muchas formas de crear asignaciones. Una opción es utilizar el asistente de mapeo en el official Joypads demo. Una vez que tenga un mapeo funcional para su control, puede probarlo definiendo la variable de entorno SDL_GAMECONTROLLERCONFIG antes de ejecutar Godot:

export SDL_GAMECONTROLLERCONFIG="your:mapping:here"
./path/to/godot.x86_64
set SDL_GAMECONTROLLERCONFIG=your:mapping:here
path\to\godot.exe
$env:SDL_GAMECONTROLLERCONFIG="your:mapping:here"
path\to\godot.exe

Para probar asignaciones en plataformas que no son de escritorio o para distribuir su proyecto con asignaciones de controles adicionales, puede agregarlas llamando a : ref: Input.add_joy_mapping() tan pronto como sea posible en la función del script _ready().

Mi control funciona en una plataforma determinada, pero no en otra plataforma.

macOS

Actualmente, los controles sólo son compatibles con Mac basados en x86. Esto significa que los controladores no funcionarán en Mac con procesadores ARM como el Apple M1.

Linux

Antes de Godot 3.3, los binarios oficiales de Godot se compilaban con soporte de udev, pero los binarios autocompilados se compilaban sin soporte de udev a menos que se pasara udev=yes en la línea de comandos de SCons. Esto hizo que el soporte de hotplugging del control no estuviera disponible en binarios autocompilados.

HTML5

El soporte del control de HTML5 es a menudo menos confiable en comparación con las plataformas "nativas". La calidad de la compatibilidad con el control tiende a variar enormemente entre los navegadores. Como resultado, es posible que deba indicar a sus jugadores que usen un navegador diferente si no pueden hacer que su control funcione.

Además, tenga en cuenta que la compatibilidad con el controlador se mejoró significativamente en Godot 3.3 y versiones posteriores.