Módulo Input
Input reparte la entrada del jugador en acciones: «saltar», «disparar», «izquierda». Cada acción es un número del 0 al 15, y con map() la asocias a una tecla (en Windows) o al pin GPIO de un botón (en las placas). El juego pregunta después por la acción con pressed(), sin saber qué hay detrás. Con set(), otra fuente (un mando I2C, el táctil) puede mover las mismas acciones.

use Input
Plataformas
| Windows | ESP32 / ESP32-S3 | ESP32-P4 | ESP32-S31 | |
|---|---|---|---|---|
Qué asocia map() | Una tecla, por su nombre | Un pin GPIO, de 0 a 63 | Un pin GPIO, de 0 a 63 | Un pin GPIO, de 0 a 63, o una tecla de un teclado USB |
| Cuándo cambia lo que lee | Las teclas, solo dentro de Display.update() | Al consultarlo | Al consultarlo | Al consultarlo |
Cada plataforma acepta un solo tipo: en Windows, un número de pin lanza ERR_TYPE_MISMATCH, y en las placas lo lanza un nombre de tecla (salvo en el ESP32-S31). Para que el mismo programa funcione en todas, elige el mapeo con platform():
use Input
const SALTAR = 0
if (platform() == HW_WIN32) then
Input.map(SALTAR, "SPACE") // en Windows, la barra espaciadora
else
Input.map(SALTAR, 15) // en la placa, un botón entre el pin 15 y GND
end
- Qué pin lleva cada botón de tu placa, el mando I2C y el teclado USB del ESP32-S31: Botones, pines y mando.
- En un juego con salas, los controles de la pestaña Game los mapea
SceneInputMap(): ver La sala y el juego.
Funciones
| Función | Qué hace | Devuelve |
|---|---|---|
map(acción, tecla o pin) | Asocia la acción a una tecla o a un pin. | true |
pressed(acción) | Dice si la acción está pulsada. | true o false |
justPressed(acción) | Dice si la acción se acaba de pulsar. | true o false |
released(acción) | Dice si la acción se acaba de soltar. | true o false |
set(acción, estado) | Pone el estado de la acción desde tu programa. | true |
update() | Vuelve a leer las entradas. | true |
Todas las funciones lanzan sus errores, así que se capturan con try:
- un número de argumentos que no es el suyo:
ERR_INVALID_ARG_NUMBER; - una acción que no es un entero:
ERR_TYPE_MISMATCH; - una acción fuera de 0 a 15:
ERR_INVALID_VALUE.
map
map(acción, tecla o pin) asocia la acción a una tecla o a un pin.
use Input
// Un juego con el teclado
Input.map(0, "W") // arriba
Input.map(1, "S") // abajo
Input.map(2, "A") // izquierda
Input.map(3, "D") // derecha
Input.map(4, "SPACE") // saltar
Input.map(5, "CTRL") // disparar
| Parámetro | Tipo | Qué es |
|---|---|---|
acción | entero | La acción, de 0 a 15. |
tecla o pin | cadena o entero | En Windows, el nombre de la tecla. En las placas, el número de pin, de 0 a 63. En el ESP32-S31, cualquiera de los dos. |
Devuelve true. Además de los errores de todas, lanza:
- con un tipo que la plataforma no admite (un número en Windows, un nombre en las placas):
ERR_TYPE_MISMATCH; - con un nombre de tecla que no existe, o un pin fuera de 0 a 63:
ERR_INVALID_VALUE.
Volver a mapear una acción le cambia la tecla o el pin, borra lo que hubiera puesto set() y la deja suelta.
En las placas, el pin queda como entrada con la resistencia de pull-up interna: conecta el botón entre el pin y GND. La acción está pulsada mientras el pin está a nivel bajo. La VM no comprueba que el pin exista en tu placa: solo que esté entre 0 y 63.
En el ESP32 (no en el S3), los pines 34 a 39 no tienen resistencia de pull-up interna. Un botón en ellos, sin una resistencia externa entre el pin y 3,3 V, deja el pin al aire y la acción no lee bien el botón. Usa otro pin o pon la resistencia. Los pines que no valen para un botón en cada chip están en Botones, pines y mando.
Las teclas
En Windows y en el teclado USB del ESP32-S31, las teclas se nombran así, en mayúsculas ("space" da ERR_INVALID_VALUE):
| Grupo | Teclas |
|---|---|
| Letras | A a Z |
| Números | 0 a 9 |
| Flechas | UP, DOWN, LEFT, RIGHT |
| Especiales | SPACE, ENTER, ESC, TAB |
| Modificadores | SHIFT, CTRL, ALT (las de la izquierda) |
pressed
pressed(acción) devuelve true mientras la acción está pulsada: por su tecla o su pin, o por set(). Una acción sin mapear devuelve false.
use Input
const IZQUIERDA = 2
const DERECHA = 3
var x = 160
var velocidad = 2
Input.map(IZQUIERDA, "A")
Input.map(DERECHA, "D")
// En cada fotograma: movimiento continuo mientras se mantiene pulsada
if (Input.pressed(IZQUIERDA)) then
x = x - velocidad
end
if (Input.pressed(DERECHA)) then
x = x + velocidad
end
Es la consulta segura: si la lees una vez por fotograma, ves todas las pulsaciones que duran al menos un fotograma (ver Cuándo se leen las entradas).
justPressed
justPressed(acción) devuelve true si la acción ha pasado de suelta a pulsada desde la lectura anterior de las entradas. Sirve para lo que pasa una vez por pulsación: saltar, disparar.
use Input
const SALTAR = 4
Input.map(SALTAR, "SPACE")
if (Input.justPressed(SALTAR)) then
println("¡Salto!")
end
justPressed puede perder pulsaciones en la 0.9.7La VM vuelve a leer las entradas cada vez que consultas una acción en un milisegundo distinto del de la lectura anterior, y cada lectura pasa el estado de ahora a «anterior» (ver Cuándo se leen las entradas). El flanco de justPressed() y released() solo dura hasta la siguiente lectura. Si en un mismo fotograma consultas varias veces las entradas (la misma acción u otras) y entre una consulta y otra cambia el milisegundo, la segunda lectura borra el flanco y la pulsación se pierde. Es un problema conocido de la 0.9.7.
Lee pressed() una sola vez por fotograma para cada acción y calcula los flancos a mano:
use Input
const SALTAR = 4
Input.map(SALTAR, "SPACE")
// Antes del bucle principal
var saltarAntes = false
// En cada fotograma
var saltar = Input.pressed(SALTAR)
var saltarPulsado = saltar and not saltarAntes // en lugar de Input.justPressed(SALTAR)
var saltarSoltado = not saltar and saltarAntes // en lugar de Input.released(SALTAR)
saltarAntes = saltar
released
released(acción) devuelve true si la acción ha pasado de pulsada a suelta desde la lectura anterior de las entradas. Pierde flancos igual que justPressed(): usa el mismo rodeo.
use Input
const SALTAR = 4
Input.map(SALTAR, "SPACE")
if (Input.released(SALTAR)) then
println("Has soltado el salto")
end
set
set(acción, estado) pone el estado de una acción desde tu programa. Es la fuente externa de la acción: un driver de mando I2C, un expansor de puertos o el táctil pueden alimentar las mismas acciones que el teclado o los GPIO, y el juego sigue leyendo pressed(), justPressed() y released() sin saber qué hay detrás.
use Input
const SALTAR = 4
var botonA = false // lo que lee tu driver del mando
// En cada fotograma, el driver del mando pone el estado del botón
Input.set(SALTAR, botonA)
if (Input.justPressed(SALTAR)) then
println("¡Salto!")
end
| Parámetro | Tipo | Qué es |
|---|---|---|
acción | entero | La acción, de 0 a 15. |
estado | booleano | true si la acción está pulsada. También vale un entero: 0 es suelta. Otro tipo lanza ERR_TYPE_MISMATCH. |
Devuelve true.
- Si la acción tiene además una tecla o un pin, las dos fuentes se suman: la acción está pulsada si lo está cualquiera de las dos. El flanco se calcula como siempre, al releer las entradas.
- Si la acción no tiene tecla ni pin,
set()la deja mapeada solo con esta fuente, y el flanco dejustPressed()oreleased()se calcula en el propioset(): dura hasta la siguiente llamada, por muchas veces que consultes en medio. Llama aset()una vez por fotograma. map()sobre esa acción borra la fuente externa.
update
update() vuelve a leer las entradas, como haría la siguiente consulta, y devuelve true. Si cae en el mismo milisegundo que la lectura anterior, no hace nada. Casi nunca hace falta: pressed(), justPressed() y released() ya leen solas.
Cuándo se leen las entradas
La VM no lee las entradas a un ritmo fijo:
- Las lee al consultarlas. Cada vez que llamas a
pressed(),justPressed(),released()oupdate()en un milisegundo distinto del de la lectura anterior, la VM vuelve a leer todas las acciones que tienen tecla o pin. Las consultas que caen en el mismo milisegundo comparten la lectura. - Cada lectura pasa el estado de ahora a «anterior».
justPressed()yreleased()comparan los dos: por eso su flanco solo dura hasta la siguiente lectura. - En Windows, el teclado solo cambia dentro de
Display.update(), que es donde la ventana recibe las pulsaciones. SinDisplay.update()en el bucle, las teclas no cambian nunca. En las placas, el pin y el teclado USB se leen en el momento. - Una acción que solo mueve
set()no se relee: su estado cambia en cadaset().
Lo seguro es leer cada acción una vez por fotograma con pressed(), guardar el valor en una variable y calcular a mano los flancos que necesites, como en el Ejemplo completo.
Ejemplo completo
Un cuadrado que se mueve con las flechas, cuenta los saltos y se cierra con ESC. Lee cada acción una vez por fotograma y calcula el flanco del salto a mano.
use Display, Input
const IZQUIERDA = 0
const DERECHA = 1
const SALTAR = 2
const SALIR = 3
if (platform() == HW_WIN32) then
Input.map(IZQUIERDA, "LEFT")
Input.map(DERECHA, "RIGHT")
Input.map(SALTAR, "SPACE")
Input.map(SALIR, "ESC")
else
// Pines de ejemplo: pon los de los botones de tu placa
Input.map(IZQUIERDA, 32)
Input.map(DERECHA, 33)
Input.map(SALTAR, 25)
Input.map(SALIR, 26)
end
Display.open(320, 240)
Display.mode(2)
Display.fps = 30
var draw = Display.draw
var x = 160
var saltos = 0
var saltarAntes = false
var salir = false
while (not salir)
// Cada acción, una vez por fotograma
var izquierda = Input.pressed(IZQUIERDA)
var derecha = Input.pressed(DERECHA)
var saltar = Input.pressed(SALTAR)
salir = Input.pressed(SALIR)
if (izquierda) then
x = x - 3
end
if (derecha) then
x = x + 3
end
if (saltar and not saltarAntes) then // el flanco, a mano
saltos = saltos + 1
end
saltarAntes = saltar
draw.cls(0x000000)
draw.color = 0x00FF00
draw.rect(x - 8, 112, 16, 16, true)
draw.text(8, 8, "Saltos: " + saltos.toString(), 0xFFFFFF)
Display.update() // en Windows, aquí cambian las teclas
end
Display.close()
Trampas y problemas conocidos
justPressed()yreleased()pueden perder pulsaciones si consultas las entradas varias veces en el mismo fotograma: ver justPressed.- En Windows, sin
Display.update()no cambia ninguna tecla. El teclado se lee en los mensajes de la ventana, que se atienden ahí. - Las teclas, en mayúsculas:
"SPACE", no"space". - Como mucho 16 acciones, de 0 a 15. Si necesitas más, haz que la misma acción signifique cosas distintas según el momento del juego (en un menú, en la partida).
- En el ESP32-S31, una acción tiene un pin o una tecla, no los dos: el último
map()sustituye al anterior. Para leer los dos, usa dos acciones, oset(). - Input no filtra los rebotes de un botón. Un botón mecánico puede abrirse y cerrarse varias veces al pulsarlo, y cada cambio que caiga en una lectura distinta es un flanco. Si te pasa, ignora los cambios durante unos milisegundos después de cada uno.
- Al terminar el programa, las acciones vuelven a estar sin mapear, también cuando la placa vuelve a cargar el programa sin reiniciarse.