Entrada para juegos simplificado
Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
Imagine un personaje del juego llamado "Bob el Carnicero" parado solo en una habitación oscura mientras hordas de zombis mutantes salchichas comienzan a entrar por las puertas y las ventanas rotas. En este punto, sería una buena idea para Bob comenzar a bombardear a los zombis de embutidos en pequeños trozos de carne, pero ¿cómo hará Bob eso en un juego multiplataforma? ¿El jugador tendrá que presionar una o más teclas en un teclado, hacer clic con el mouse, tocar la pantalla o presionar un botón en un gamepad?
Cuando
programe un juego multiplataforma, este es el tipo de cosas con las que
probablemente pasará mucho tiempo batallando si no está preparado para
ello. Si no tiene cuidado, podría terminar con declaraciones masivas,
tipo
spaghetti if
o declaraciones switch
para tratar con todos los
diferentes dispositivos de entrada.
En este tutorial, vamos a simplificar las cosas creando una única clase que unificará varios dispositivos de entrada. Cada instancia de la clase representará una acción o comportamiento específico del juego (como "disparar", "ejecutar" o "saltar") y se le puede indicar que escuche varias teclas, botones y punteros en múltiples dispositivos de entrada.
Nota: El lenguaje de programación utilizado en este tutorial es JavaScript, pero la técnica que se usa para unificar múltiples dispositivos de entrada puede transferirse fácilmente a cualquier otro lenguaje de programación multiplataforma que proporcione API para dispositivos de entrada.
Disparando las salchichas
Antes de comenzar a escribir el código para la clase que vamos a crear en este tutorial, echemos un vistazo rápido a cómo la clase podría ser utilizada.
1 |
// Create an input for the "shoot" action.
|
2 |
shoot = new GameInput(); |
3 |
|
4 |
// Tell the input what to react to.
|
5 |
shoot.add( GameInput.KEYBOARD_SPACE ); |
6 |
shoot.add( GameInput.GAMEPAD_RT ); |
7 |
|
8 |
// During each game update, check the input.
|
9 |
function update() { |
10 |
if( shoot.value > 0 ) { |
11 |
// Tell Bob to shoot the mutant sausage zombies!
|
12 |
} else { |
13 |
// Tell Bob to stop shooting.
|
14 |
}
|
15 |
}
|
GameInput
es la clase que vamos a crear, y puedes ver cuánto más simple hará las cosas. La
propiedad shoot.value
es un número y será un valor positivo si se
presiona la barra espaciadora de un teclado o se presiona el gatillo
derecho en un gamepad. Si no se presiona ni la barra espaciadora ni el
disparador derecho, el valor será cero.
Empezando
Lo primero que debemos
hacer es crear un cierre de función para la clase GameInput
. La
mayor parte del código que vamos a escribir no es realmente parte de la
clase, pero debe ser accesible desde dentro de la clase mientras
permanece oculto de todo lo demás. El cierre de una función nos permite
hacer eso en JavaScript.
(En un lenguaje de programación como ActionScript o C #, podría simplemente usar miembros privados de la clase, pero eso no es un lujo que tenemos en JavaScript, desafortunadamente).
1 |
(function(){ |
2 |
// code goes here
|
3 |
})();
|
El resto del código en este tutorial reemplazará el comentario "el código va aquí".
Las variables
El código solo necesita un puñado de variables para definir fuera de las funciones, y esas variables son las siguientes.
1 |
var KEYBOARD = 1; |
2 |
var POINTER = 2; |
3 |
var GAMEPAD = 3; |
4 |
var DEVICE = 16; |
5 |
var CODE = 8; |
6 |
|
7 |
var __pointer = { |
8 |
currentX : 0, |
9 |
currentY : 0, |
10 |
previousX : 0, |
11 |
previousY : 0, |
12 |
distanceX : 0, |
13 |
distanceY : 0, |
14 |
identifier : 0, |
15 |
moved : false, |
16 |
pressed : false |
17 |
};
|
18 |
|
19 |
var __keyboard = {}; |
20 |
var __inputs = []; |
21 |
var __channels = []; |
22 |
|
23 |
var __mouseDetected = false; |
24 |
var __touchDetected = false; |
Los valores constantes de KEYBOARD
, POINTER
, GAMEPAD
, DEVICE
y CODE
se
utilizan para definir canales de dispositivo de entrada, como
GameInput.KEYBOARD_SPACE
, y su uso se aclarará más adelante en el
tutorial.
El
objeto __pointer
contiene propiedades que son relevantes para los
dispositivos de entrada de mouse y pantalla táctil, y el objeto
__keyboard
se utiliza para realizar un seguimiento de los estados de las
teclas del teclado. Las
matrices __inputs
y __channels
se usan para almacenar instancias de
GameInput
y cualquier canal de dispositivo de entrada agregado a esas
instancias. Finalmente, __mouseDetected
y __touchDetected
indican si se
ha detectado un mouse o una pantalla táctil.
Nota: Las variables no necesitan un prefijo con dos guiones bajos; esa es simplemente la convención de codificación que he elegido usar para el código en este tutorial. Ayuda a separarlos de las variables definidas en funciones.
Las funciones
Aquí viene la mayor parte del código, por lo que es posible que desee tomar un café o algo así antes de comenzar a leer esta parte.
Estas funciones se definen después de las variables en la sección anterior de este tutorial, y se definen en orden de aparición.
1 |
// Initializes the input system.
|
2 |
function main() { |
3 |
// Expose the GameInput constructor.
|
4 |
window.GameInput = GameInput; |
5 |
|
6 |
// Add the event listeners.
|
7 |
addMouseListeners(); |
8 |
addTouchListeners(); |
9 |
addKeyboardListeners(); |
10 |
|
11 |
// Some UI actions we should prevent in a game.
|
12 |
window.addEventListener( "contextmenu", killEvent, true ); |
13 |
window.addEventListener( "selectstart", killEvent, true ); |
14 |
|
15 |
// Start the update loop.
|
16 |
window.requestAnimationFrame( update ); |
17 |
}
|
La función main ()
se llama al final del código, es decir, al final del cierre de la función que creamos anteriormente. Hace lo que dice en la lata y lo ejecuta todo para que se pueda usar la clase GameInput
.
Una
cosa que debo llamar su atención es el uso de la función
requestAnimationFrame()
, que es parte de la especificación de W3C
Animation Timing. Los juegos y las aplicaciones
modernos usan esta función para ejecutar sus bucles de actualización o
representación, ya que ha sido altamente optimizado para ese propósito
en la mayoría de los navegadores web.
1 |
// Updates the input system.
|
2 |
function update() { |
3 |
window.requestAnimationFrame( update ); |
4 |
|
5 |
// Update the pointer values first.
|
6 |
updatePointer(); |
7 |
|
8 |
var i = __inputs.length; |
9 |
var input = null; |
10 |
var channels = null; |
11 |
|
12 |
while( i -- > 0 ) { |
13 |
input = __inputs[ i ]; |
14 |
channels = __channels[ i ]; |
15 |
|
16 |
if( input.enabled === true ) { |
17 |
updateInput( input, channels ); |
18 |
}
|
19 |
else { |
20 |
input.value = 0; |
21 |
}
|
22 |
}
|
23 |
}
|
La función update()
rueda a través de la lista de instancias GameInput
activas y actualiza las que están habilitadas. La siguiente función updateInput()
es bastante larga, por lo que no agregaré el código aquí; Puede ver el código completo descargando los archivos fuente.
1 |
// Updates a GameInput instance.
|
2 |
function updateInput( input, channels ) { |
3 |
// note: see the source files
|
4 |
}
|
La
función updateInput()
examina los canales del dispositivo de entrada
que se han agregado a una instancia GameInput
y determina en qué se debe
establecer la propiedad value
de la instancia GameInput
. Como
se ve en el código de ejemplo Disparos a las salchichas Shooting the Sausages, la propiedad
value
indica si se está activando un canal de dispositivo de entrada,
y eso permite que un juego reaccione en consecuencia, tal vez
diciéndole a Bob que dispare a los zombis mutantes de salchichas.
1 |
// Updates the value of a GameInput instance.
|
2 |
function updateValue( input, value, threshold ) { |
3 |
if( threshold !== undefined ) { |
4 |
if( value < threshold ) { |
5 |
value = 0; |
6 |
}
|
7 |
}
|
8 |
|
9 |
// The highest value has priority.
|
10 |
if( input.value < value ) { |
11 |
input.value = value; |
12 |
}
|
13 |
}
|
La función updateValue ()
determina si la propiedad value
de una instancia de GameInput
debe actualizarse. El
umbral threshold
se usa principalmente para evitar que los canales de entrada de
dispositivos analógicos, como los botones y palos del gamepad, no se
reinicien correctamente al activar constantemente una instancia de
GameInput
. Esto sucede bastante a menudo con gamepads defectuosos o sucios.
Al
igual que la función updateInput()
, la siguiente función updatePointer()
es bastante larga, por lo que no agregaré el código aquí. Puede ver el código completo descargando los archivos fuente.
1 |
// Updates the pointer values.
|
2 |
function updatePointer() { |
3 |
// note: see the source files
|
4 |
}
|
La función updatePointer()
actualiza las propiedades en el objeto __pointer
. En
pocas palabras, la función sujeta la posición del puntero para
asegurarse de que no abandona la ventana de la ventana del navegador web
y calcula la distancia que ha movido el puntero desde la última
actualización.
1 |
// Called when a mouse input device is detected.
|
2 |
function mouseDetected() { |
3 |
if( __mouseDetected === false ) { |
4 |
__mouseDetected = true; |
5 |
|
6 |
// Ignore touch events if a mouse is being used.
|
7 |
removeTouchListeners(); |
8 |
}
|
9 |
}
|
10 |
|
11 |
// Called when a touch-screen input device is detected.
|
12 |
function touchDetected() { |
13 |
if( __touchDetected === false ) { |
14 |
__touchDetected = true; |
15 |
|
16 |
// Ignore mouse events if a touch-screen is being used.
|
17 |
removeMouseListeners(); |
18 |
}
|
19 |
}
|
Las funciones mouseDetected()
y touchDetected()
le dicen al código que ignore un dispositivo de entrada u otro. Si se detecta un mouse antes de una pantalla táctil, se ignorará la
pantalla táctil. Si se detecta una pantalla táctil antes de un mouse, se
ignorará el mouse.
1 |
// Called when a pointer-like input device is pressed.
|
2 |
function pointerPressed( x, y, identifier ) { |
3 |
__pointer.identifier = identifier; |
4 |
__pointer.pressed = true; |
5 |
|
6 |
pointerMoved( x, y ); |
7 |
}
|
8 |
|
9 |
// Called when a pointer-like input device is released.
|
10 |
function pointerReleased() { |
11 |
__pointer.identifier = 0; |
12 |
__pointer.pressed = false; |
13 |
}
|
14 |
|
15 |
// Called when a pointer-like input device is moved.
|
16 |
function pointerMoved( x, y ) { |
17 |
__pointer.currentX = x >>> 0; |
18 |
__pointer.currentY = y >>> 0; |
19 |
|
20 |
if( __pointer.moved === false ) { |
21 |
__pointer.moved = true; |
22 |
__pointer.previousX = __pointer.currentX; |
23 |
__pointer.previousY = __pointer.currentY; |
24 |
}
|
25 |
}
|
Las funciones pointerPressed()
, pointerReleased()
y pointerMoved()
manejan la entrada desde un mouse o una pantalla táctil. Las tres funciones simplemente actualizan propiedades en el __pointer
objeto.
Después de esas tres funciones, tenemos un puñado de funciones de manejo de eventos de JavaScript estándar. Las funciones se explican por sí mismas, así que no agregaré el código aquí; Puede ver el código completo descargando los archivos fuente.
1 |
// Adds an input device channel to a GameInput instance.
|
2 |
function inputAdd( input, channel ) { |
3 |
var i = __inputs.indexOf( input ); |
4 |
|
5 |
if( i === -1 ) { |
6 |
__inputs.push( input ); |
7 |
__channels.push( [ channel ] ); |
8 |
return; |
9 |
}
|
10 |
|
11 |
var ca = __channels[ i ]; |
12 |
var ci = ca.indexOf( channel ); |
13 |
|
14 |
if( ci === -1 ) { |
15 |
ca.push( channel ); |
16 |
}
|
17 |
}
|
18 |
|
19 |
// Removes an input device channel to a GameInput instance.
|
20 |
function inputRemove( input, channel ) { |
21 |
var i = __inputs.indexOf( input ); |
22 |
|
23 |
if( i === -1 ) { |
24 |
return; |
25 |
}
|
26 |
|
27 |
var ca = __channels[ i ]; |
28 |
var ci = ca.indexOf( channel ); |
29 |
|
30 |
if( ci !== -1 ) { |
31 |
ca.splice( ci, 1 ); |
32 |
|
33 |
if( ca.length === 0 ) { |
34 |
__inputs.splice( i, 1 ); |
35 |
__channels.splice( i, 1 ); |
36 |
}
|
37 |
}
|
38 |
}
|
39 |
|
40 |
// Resets a GameInput instance.
|
41 |
function inputReset( input ) { |
42 |
var i = __inputs.indexOf( input ); |
43 |
|
44 |
if( i !== -1 ) { |
45 |
__inputs.splice( i, 1 ); |
46 |
__channels.splice( i, 1 ); |
47 |
}
|
48 |
|
49 |
input.value = 0; |
50 |
input.enabled = true; |
51 |
}
|
Las funciones inputAdd ()
, inputRemove ()
y inputReset ()
se invocan desde una instancia GameInput
(ver a continuación). Las funciones modifican las matrices __inputs
y __channels
según lo que se necesite hacer.
Una
instancia de GameInput
se considera activa y se agrega a la matriz
__inputs
, cuando se ha agregado un canal de dispositivo de entrada a la
instancia de GameInput
. Si una instancia de GameInput
activa tiene eliminados todos sus canales de dispositivos de entrada, la
instancia GameInput
se considera inactiva y se elimina de la matriz
__inputs
.
Ahora llegamos a la clase GameInput
.
1 |
// GameInput constructor.
|
2 |
function GameInput() {} |
3 |
|
4 |
GameInput.prototype = { |
5 |
value : 0, |
6 |
enabled : true, |
7 |
|
8 |
// Adds an input device channel.
|
9 |
add : function( channel ) { |
10 |
inputAdd( this, channel ); |
11 |
},
|
12 |
|
13 |
// Removes an input device channel.
|
14 |
remove : function( channel ) { |
15 |
inputRemove( this, channel ); |
16 |
},
|
17 |
|
18 |
// Removes all input device channels.
|
19 |
reset : function() { |
20 |
inputReset( this ); |
21 |
}
|
22 |
};
|
Sí, eso es todo lo que hay, es una clase súper ligera que esencialmente actúa como una interfaz para el código principal. La propiedad value
es un número que va de 0
(cero) a 1
(uno). Si
el valor es 0
, significa que la instancia de GameInput
no recibe nada
de ningún canal de dispositivo de entrada que se le haya agregado.
La
clase GameInput
tiene algunas propiedades estáticas, por lo que las
agregaremos ahora.
1 |
// The X position of the pointer within the window viewport.
|
2 |
GameInput.pointerX = 0; |
3 |
|
4 |
// The Y position of the pointer within the window viewport.
|
5 |
GameInput.pointerY = 0; |
6 |
|
7 |
// The distance the pointer has to move, in pixels per frame, to
|
8 |
// cause the value of a GameInput instance to equal 1.0.
|
9 |
GameInput.pointerSpeed = 10; |
Canales de dispositivo de teclado:
1 |
GameInput.KEYBOARD_A = KEYBOARD << DEVICE | 65 << CODE; |
2 |
GameInput.KEYBOARD_B = KEYBOARD << DEVICE | 66 << CODE; |
3 |
GameInput.KEYBOARD_C = KEYBOARD << DEVICE | 67 << CODE; |
4 |
GameInput.KEYBOARD_D = KEYBOARD << DEVICE | 68 << CODE; |
5 |
GameInput.KEYBOARD_E = KEYBOARD << DEVICE | 69 << CODE; |
6 |
GameInput.KEYBOARD_F = KEYBOARD << DEVICE | 70 << CODE; |
7 |
GameInput.KEYBOARD_G = KEYBOARD << DEVICE | 71 << CODE; |
8 |
GameInput.KEYBOARD_H = KEYBOARD << DEVICE | 72 << CODE; |
9 |
GameInput.KEYBOARD_I = KEYBOARD << DEVICE | 73 << CODE; |
10 |
GameInput.KEYBOARD_J = KEYBOARD << DEVICE | 74 << CODE; |
11 |
GameInput.KEYBOARD_K = KEYBOARD << DEVICE | 75 << CODE; |
12 |
GameInput.KEYBOARD_L = KEYBOARD << DEVICE | 76 << CODE; |
13 |
GameInput.KEYBOARD_M = KEYBOARD << DEVICE | 77 << CODE; |
14 |
GameInput.KEYBOARD_N = KEYBOARD << DEVICE | 78 << CODE; |
15 |
GameInput.KEYBOARD_O = KEYBOARD << DEVICE | 79 << CODE; |
16 |
GameInput.KEYBOARD_P = KEYBOARD << DEVICE | 80 << CODE; |
17 |
GameInput.KEYBOARD_Q = KEYBOARD << DEVICE | 81 << CODE; |
18 |
GameInput.KEYBOARD_R = KEYBOARD << DEVICE | 82 << CODE; |
19 |
GameInput.KEYBOARD_S = KEYBOARD << DEVICE | 83 << CODE; |
20 |
GameInput.KEYBOARD_T = KEYBOARD << DEVICE | 84 << CODE; |
21 |
GameInput.KEYBOARD_U = KEYBOARD << DEVICE | 85 << CODE; |
22 |
GameInput.KEYBOARD_V = KEYBOARD << DEVICE | 86 << CODE; |
23 |
GameInput.KEYBOARD_W = KEYBOARD << DEVICE | 87 << CODE; |
24 |
GameInput.KEYBOARD_X = KEYBOARD << DEVICE | 88 << CODE; |
25 |
GameInput.KEYBOARD_Y = KEYBOARD << DEVICE | 89 << CODE; |
26 |
GameInput.KEYBOARD_Z = KEYBOARD << DEVICE | 90 << CODE; |
27 |
|
28 |
GameInput.KEYBOARD_0 = KEYBOARD << DEVICE | 48 << CODE; |
29 |
GameInput.KEYBOARD_1 = KEYBOARD << DEVICE | 49 << CODE; |
30 |
GameInput.KEYBOARD_2 = KEYBOARD << DEVICE | 50 << CODE; |
31 |
GameInput.KEYBOARD_3 = KEYBOARD << DEVICE | 51 << CODE; |
32 |
GameInput.KEYBOARD_4 = KEYBOARD << DEVICE | 52 << CODE; |
33 |
GameInput.KEYBOARD_5 = KEYBOARD << DEVICE | 53 << CODE; |
34 |
GameInput.KEYBOARD_6 = KEYBOARD << DEVICE | 54 << CODE; |
35 |
GameInput.KEYBOARD_7 = KEYBOARD << DEVICE | 55 << CODE; |
36 |
GameInput.KEYBOARD_8 = KEYBOARD << DEVICE | 56 << CODE; |
37 |
GameInput.KEYBOARD_9 = KEYBOARD << DEVICE | 57 << CODE; |
38 |
|
39 |
GameInput.KEYBOARD_UP = KEYBOARD << DEVICE | 38 << CODE; |
40 |
GameInput.KEYBOARD_DOWN = KEYBOARD << DEVICE | 40 << CODE; |
41 |
GameInput.KEYBOARD_LEFT = KEYBOARD << DEVICE | 37 << CODE; |
42 |
GameInput.KEYBOARD_RIGHT = KEYBOARD << DEVICE | 39 << CODE; |
43 |
GameInput.KEYBOARD_SPACE = KEYBOARD << DEVICE | 32 << CODE; |
44 |
GameInput.KEYBOARD_SHIFT = KEYBOARD << DEVICE | 16 << CODE; |
Canales del dispositivo de puntero:
1 |
GameInput.POINTER_UP = POINTER << DEVICE | 0 << CODE; |
2 |
GameInput.POINTER_DOWN = POINTER << DEVICE | 1 << CODE; |
3 |
GameInput.POINTER_LEFT = POINTER << DEVICE | 2 << CODE; |
4 |
GameInput.POINTER_RIGHT = POINTER << DEVICE | 3 << CODE; |
5 |
GameInput.POINTER_PRESS = POINTER << DEVICE | 4 << CODE; |
Canales del dispositivo Gamepad:
1 |
GameInput.GAMEPAD_A = GAMEPAD << DEVICE | 0 << CODE; |
2 |
GameInput.GAMEPAD_B = GAMEPAD << DEVICE | 1 << CODE; |
3 |
GameInput.GAMEPAD_X = GAMEPAD << DEVICE | 2 << CODE; |
4 |
GameInput.GAMEPAD_Y = GAMEPAD << DEVICE | 3 << CODE; |
5 |
GameInput.GAMEPAD_LB = GAMEPAD << DEVICE | 4 << CODE; |
6 |
GameInput.GAMEPAD_RB = GAMEPAD << DEVICE | 5 << CODE; |
7 |
GameInput.GAMEPAD_LT = GAMEPAD << DEVICE | 6 << CODE; |
8 |
GameInput.GAMEPAD_RT = GAMEPAD << DEVICE | 7 << CODE; |
9 |
GameInput.GAMEPAD_START = GAMEPAD << DEVICE | 8 << CODE; |
10 |
GameInput.GAMEPAD_SELECT = GAMEPAD << DEVICE | 9 << CODE; |
11 |
GameInput.GAMEPAD_L = GAMEPAD << DEVICE | 10 << CODE; |
12 |
GameInput.GAMEPAD_R = GAMEPAD << DEVICE | 11 << CODE; |
13 |
GameInput.GAMEPAD_UP = GAMEPAD << DEVICE | 12 << CODE; |
14 |
GameInput.GAMEPAD_DOWN = GAMEPAD << DEVICE | 13 << CODE; |
15 |
GameInput.GAMEPAD_LEFT = GAMEPAD << DEVICE | 14 << CODE; |
16 |
GameInput.GAMEPAD_RIGHT = GAMEPAD << DEVICE | 15 << CODE; |
17 |
GameInput.GAMEPAD_L_UP = GAMEPAD << DEVICE | 16 << CODE; |
18 |
GameInput.GAMEPAD_L_DOWN = GAMEPAD << DEVICE | 17 << CODE; |
19 |
GameInput.GAMEPAD_L_LEFT = GAMEPAD << DEVICE | 18 << CODE; |
20 |
GameInput.GAMEPAD_L_RIGHT = GAMEPAD << DEVICE | 19 << CODE; |
21 |
GameInput.GAMEPAD_R_UP = GAMEPAD << DEVICE | 20 << CODE; |
22 |
GameInput.GAMEPAD_R_DOWN = GAMEPAD << DEVICE | 21 << CODE; |
23 |
GameInput.GAMEPAD_R_LEFT = GAMEPAD << DEVICE | 22 << CODE; |
24 |
GameInput.GAMEPAD_R_RIGHT = GAMEPAD << DEVICE | 23 << CODE; |
Para finalizar el código, simplemente necesitamos llamar a la función main()
.
1 |
// Initialize the input system.
|
2 |
main(); |
Y eso es todo el código. De nuevo, todo está disponible en los archivos fuente.
¡Huye!
Antes de completar el tutorial con una conclusión, echemos un
vistazo a un ejemplo más de cómo se puede usar la clase GameInput
. Esta
vez, le daremos a Bob la habilidad de moverse y saltar porque las
hordas de zombis mutantes pueden convertirse en demasiado para él solo.
1 |
// Create the inputs.
|
2 |
var jump = new GameInput(); |
3 |
var moveLeft = new GameInput(); |
4 |
var moveRight = new GameInput(); |
5 |
|
6 |
// Tell the inputs what to react to.
|
7 |
jump.add( GameInput.KEYBOARD_UP ); |
8 |
jump.add( GameInput.KEYBOARD_W ); |
9 |
jump.add( GameInput.GAMEPAD_A ); |
10 |
moveLeft.add( GameInput.KEYBOARD_LEFT ); |
11 |
moveLeft.add( GameInput.KEYBOARD_A ); |
12 |
moveLeft.add( GameInput.GAMEPAD_LEFT ); |
13 |
moveRight.add( GameInput.KEYBOARD_RIGHT ); |
14 |
moveRight.add( GameInput.KEYBOARD_D ); |
15 |
moveRight.add( GameInput.GAMEPAD_RIGHT ); |
16 |
|
17 |
// During each game update, check the inputs.
|
18 |
function update() { |
19 |
if( jump.value > 0 ) { |
20 |
// Tell Bob to jump.
|
21 |
} else { |
22 |
// Tell Bob to stop jumping.
|
23 |
}
|
24 |
|
25 |
if( moveLeft.value > 0 ) { |
26 |
// Tell Bob to move/run left.
|
27 |
} else { |
28 |
// Tell Bob to stop moving left.
|
29 |
}
|
30 |
|
31 |
if( moveRight.value > 0 ) { |
32 |
// Tell Bob to move/run right.
|
33 |
} else { |
34 |
// Tell Bob to stop moving right.
|
35 |
}
|
36 |
}
|
Bonito y fácil. Tenga
en cuenta que la propiedad value
de las instancias de GameInput
varía de 0
a 1
, por lo que podríamos hacer algo como cambiar la
velocidad de movimiento de Bob usando ese valor si uno de los canales de
dispositivos de entrada activos es analógico.
1 |
if( moveLeft.value > 0 ) { |
2 |
bob.x -= bob.maxDistancePerFrame * moveLeft.value; |
3 |
}
|
¡Que te diviertas!
Conclusión
Los juegos multiplataforma tienen todos una cosa en común: todos deben lidiar con una multitud de dispositivos de entrada de juegos (controladores), y lidiar con esos dispositivos de entrada puede convertirse en una tarea abrumadora. Este tutorial ha demostrado una forma de manejar múltiples dispositivos de entrada con el uso de una API simple y unificada.