Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Games
Gamedevelopment

Entrada para juegos simplificado

by
Difficulty:IntermediateLength:LongLanguages:

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.

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).

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

Canales de dispositivo de teclado:

Canales del dispositivo de puntero:

Canales del dispositivo Gamepad:

Para finalizar el código, simplemente necesitamos llamar a la función 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.

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.

¡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.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.