Buen día a todos los habrozhitel. Quiero contarles cómo volví a un desarrollador de juegos de aficionados después de más de 3 años, cambiando radicalmente la herramienta (y en el camino, mi visión del mundo), y lo que surgió de ella. Debajo del corte que:
- Una breve disposición de todos los hechos al comienzo del viaje. Al igual que la imagen "ANTES" en la publicidad en línea barata "ANTES" y "DESPUÉS".
- Una inmersión voluntaria en una interfaz moderna al estilo de "¿Dónde está el dinero, Lebowski?!"
- Ligero picor en un punto íntimo, convirtiéndose en un ardiente deseo de aprender algo nuevo haciendo algo viejo.
- Conciencia de la propia impotencia.
- Superar
- Buen final, como en estas películas tuyas.
Descargo de responsabilidad
Este artículo estuvo en borrador en Github durante dos años, su versión casi completa se escribió a fines de 2017 en busca de eventos.
Ciudadano, preséntate!
En mi artículo anterior ( https://habrahabr.ru/post/244417/ ) escribí un poco sobre mí y, más específicamente, sobre cómo yo y gamedev estamos conectados. De jure, de ninguna manera, de facto, escribo juegos y motores para el placer y la participación en competiciones cálidas y de lámparas. Desde entonces, poco ha cambiado.
Para una mayor narración y forzar la atmósfera necesaria, es importante que al comienzo de este cuento sea un desarrollador web .net profesional que pueda usar html5, css3 y ... jquery. Para reforzar el inesperado "este es un giro", agregamos que hay desconfianza y disgusto por JavaScript, sazonado con:
- malentendido franco de todo este bombo en torno al idioma;
- un conjunto de chistes sobre tipeo, obsolescencia acelerada de marcos, sorpresas de número + cadena, y más. Ya sabes, un conjunto de desarrolladores tan caballeroso y completamente estándar que usa un lenguaje más antiguo y más establecido (hey, sé que la plataforma .net es más joven que js, pero no "adulta" en el sentido literal).
Ven
Septiembre de 2017. Comencé un nuevo trabajo cálido y de lámpara con una nueva pila de tecnología (.net core web api + angular 4) y mi tarea era solo el back-end. La palabra Angular sonaba abusiva para mí, npm y nodejs estaban fuertemente asociados con batidos y un scooter giroscópico. Timlid, al ver esto y comprender, me enseñó un curso corto sobre cómo lanzar todo este shaitanismo. Al igual que en esa broma sobre Chukchi y los perros en el espacio. Recuerdo los apodos de murciélago que necesito comenzar (recordando npm run start, lo encontré extremadamente innecesario para mi naturaleza amable), y me sumerjo en un ambiente cálido y tubo LED .net core.
Octubre de 2017. La primera campana. Timlid dice que nuestro trabajador de primera línea cose 4 proyectos de inmediato y me ofrece cortar alguna sección en el área de administración. Motivando que, dicen, es fácil allí, solo repita cómo se hizo para la entidad N, solo ahora para M. Ante la risa de colegas que se escapan por un giroscopio y un vaporizador para mí, leyendo apresuradamente un breve programa educativo sobre Angular, copiando y pegando, yo Doy a luz a una sección que, con reservas, funciona. Timlid está satisfecho, estoy en estado de shock, y parece que las tareas en el backend aparecieron en el tablero ...
Pero no Hay muchos back-endors, ya hay pocas tareas para ellos y un campo sin labrar en el frente. Una nueva tarea, ya directamente en el portal, me hace tomar el asunto en serio. Los colegas se esfuerzan por meterme los pantalones y llevarme a una barbería, y durante una semana me sumerjo en materiales de lectura en Angular, TypeScript, npm, webpack y más. Por cierto, el artículo sobre Javascript moderno para dinosaurios ayudó mucho: https://habrahabr.ru/company/mailru/blog/340922/ .
Después de un tiempo, pude cerrar tareas simples de front-end, sintiéndome como un portero en ausencia de una criada. Todavía riéndome de las bromas sobre el front-end, sugiero que mis compañeros portadores se reúnan y escuchen mi experiencia de fresa y plátano. Todos se ríen, pero en secreto todos quieren entender qué tipo de burbujeo está teniendo lugar en este front-end rápido (de hecho, no).
Sin más preámbulos, vuelvo a contar el artículo anterior de Habr, sazonándolo con mi conocimiento básico de Angular. Mitap viene con una explosión, y, posteriormente, gasto una serie de esos, sobre el front-end para el backend, que, sin embargo, no es tan importante para nuestra historia. Lo único importante es que su implementación me llevó a un estudio más profundo de la pila moderna de tecnologías front-end.
Picor
En el trabajo, todo resultó, llegó un momento bastante tranquilo en la vida familiar y apareció picazón. Tal, ya sabes, pequeño, todavía bastante frágil y viviendo en algún lugar al borde del subconsciente. Los pensamientos parpadearon en mi cabeza, dicen, hace tres años, casi dejé de hacer mi hobby: programar juegos. Pero, ¿y si combinas nuevos conocimientos y ...?
Miré a WebGL durante mucho tiempo, pero antes estaba asustado por la falta de ayuda (mecanografía, autocompletado) al usarlo. Y aquí, por favor, una bala de plata inexistente en la carne, ese mismo martillo, cuando se toma, todo se convierte en clavos. TypeScript
Para mí, como persona que conocía el dolor con el infierno de devolución de llamada, var self = this, bind (this), undefined no es una función ... Entonces, TypeScript no me pareció ni siquiera un soplo de aire fresco, sino una especie de mago en una nave espacial azul, que, descendiendo de cielo, perezosamente me tiró - hijo, olvida todo lo que sabías sobre js antes, y te mostraré cuán profundo es la madriguera del conejo. ¿La analogía parece caótica y, en general, una especie de mezcolanza de otras analogías? Es cierto, como TypeScript en sí de un vistazo.
Clases, interfaces, mecanografía, asíncrono, errores de compilación y errores tipográficos, finalización de código, trabajo sin pandereta, comportamiento de comprensión comprensible en lugar de desalentar var. Por supuesto, después de un tiempo, me di cuenta de que el patrocinador de la mayor parte de esta felicidad no es TypeScript en absoluto, sino JavaScript en su versión moderna (ES6 y superior). Pero en ese momento parecía que había encontrado un profeta que llevaría a la interfaz a uno brillante, comunista El futuro. Agregue a esto el progreso lo suficientemente serio de varios IDE en el campo de Intellisense y la asistencia al desarrollador, y tal vez comprenderá mi deleite de cachorro.
Impotencia
El primer golpe serio en mi aliento fue el propio TypeScript. Los intentos de sujetarlo a un proyecto vacío me hicieron comprender: no puedo entender una maldita cosa fuera de angular y angular-cli, que hacen mucho trabajo sucio para mí. ¿Necesito un compilador? Ok, atorníllelo en package.json, instale npm, ejecute tsc y ... nada. Ah, ¿necesitas instalarlo a nivel mundial? Omitiendo los aburridos detalles de mi guerra con todo esto, diré que algún tiempo después aprendí a convertir main.ts en main.js. Pero delante de mí estaba preocupado con webpack.
Sí, ahora me doy cuenta de que era posible prescindir de él. Pero cuando está en manos torpes de Typecript, todo a su alrededor parece angular-cli. Ya después de la implementación de webpack, me doy cuenta de que el compilador TypeScript en sí mismo puede "monitorear" los cambios en los archivos, que el problema con la importación / exportación se puede resolver sin webpack.
Superar
Después de aproximadamente una semana, pude crear un proyecto en el que escribí el código TypeScript, hice clic en "Guardar" y todo salió como debería: webpack recompiló automáticamente todos mis archivos en un solo paquete, primero ejecuté el compilador TypeScript en ellos y luego solté la compilación en una carpeta separada donde copié otras cosas estáticas, y en el navegador en ese momento lite-server volvió a cargar la página. ¿Dije que todo sucedió automáticamente? No, todo sucedió automáticamente . Joy no conocía límites, y me senté a escribir un simple tirador de arena.
Donde comienza patria es el juego para mi? Por supuesto, con cosas básicas como vectores matemáticos y matrices. Superé con éxito el síndrome de No inventado aquí en el trabajo, pero en un pasatiempo no desapareció. No quería bibliotecas listas, así que me senté a escribir mis cálculos. No, eso se dice demasiado fuerte. Abrí mi marco anterior FreePascal ( https://github.com/perfectdaemon/tiny-glr/ ) y comencé a convertir las matemáticas desde allí.
Mirando hacia el futuro, diré que, en general, mi marco completamente nuevo es la conversión del viejo de Free Pascal a TypeScript. Dado más de un paréntesis de tres años en el desarrollo del juego, no podría encontrar una mejor arquitectura, ni siquiera recordar cuáles fueron las desventajas del pasado.
Después de un tiempo, comencé a quedarme sin aliento: la motivación naturalmente disminuyó, la carga de trabajo aumentó. Y luego en igdc anunció otro concurso. Y créanme, la competencia es un excelente motivador externo que establece límites temáticos, técnicos y de tiempo.
Competencia
Ya dije en mi último artículo qué es locura igdc , pero lo repetiré brevemente aquí: es una comunidad de lámparas tan cálida que realiza concursos cortos o medianos para desarrollar juegos sobre un tema determinado. Sin premios en efectivo, patrocinadores de renombre y garantías de seguridad laboral. Ah, sí, incluso sin publicidad, entusiasmo y con la participación de una donación voluntaria para hosting y dominio. Y así durante casi 15 años.
Competencia Tema - Juego de basura . Dado un paquete extenso y diverso de recursos gráficos. La tarea de los participantes es hacer el juego solo con él. El género y el tema no están limitados, se permite el uso de cualquier sonido y música, ya que el paquete contiene solo gráficos. Existe una limitación técnica histórica asociada con el lanzamiento estrictamente fuera de línea, sin instaladores, descargas y más.
Este último es un pequeño problema, ya que Chrome y la compañía prohíben muchas cosas cuando un usuario abre un archivo html localmente. Es posible que WebGL no se active, los scripts no querrán ser extraídos, sin mencionar los recursos gráficos. Hay una salida: creamos un servidor web local súper pequeño y un script de inicio para el usuario que lo recogerá y abrirá el navegador favorito del usuario en la dirección deseada.
La tarea es simple, me metí en un exe de 6 kilobytes en C # y un apodo de murciélago cercano, que define la carpeta raíz para el servidor y el puerto.
Pero, basta de este pequeño obstáculo para un objetivo grande y limpio: escribir un juego para la competencia.
Juego de competencia
Mirando los recursos, me di cuenta de que el tirador de arena con su uso resultaría bastante sólido.
Después de completar las cosas básicas, procedí a la selección de los recursos que necesitaba. El corte final en forma de un atlas de texturas se ve así:

Por cierto, algunas cosas horneadas en el atlas nunca se usaron en el juego. Después de cargar los recursos, comencé una nueva funcionalidad para mí: la animación de sprites. Fui feliz cuando era niño cuando todo resultó:

Física propia
Conectar la física de otras personas con el deseo desenfrenado de inventar todo lo mío parecía al menos blasfemo y, según me parece, ni siquiera fue considerado por mi entusiasta organismo (acabo de derrotar la animación de sprites, ¿recuerdas?). Además, ¿qué puede ser difícil en el procesamiento de colisión simple basado en rectángulos (cuadro delimitador alineado con el eje, AABB) y círculos? Muchas cosas Comenzando por atrapar a un personaje en rincones invisibles y terminando con el hecho de que llevas todos los objetos de tu mundo a rectángulos y círculos.
No fue posible resolver todos los problemas, pero, sin embargo, apareció algo de física:

Suena
Discretamente esperaba que fuera difícil. De hecho, resultó de alguna manera sospechosamente simple y eficiente. Creamos un contexto de audio, creamos un búfer de audio, pusimos música / sonidos allí en cualquier formato aceptable para el navegador (usé wav), creamos un nodo y dijimos desde qué búfer jugar.
Los sonidos que generé usando bfxr ( https://www.bfxr.net/ ).
Caqui
Muletas, decisiones ad hoc, podhachivaniya: es difícil encontrar a una persona que conozca estas palabras solo por rumores. Al final del concurso, inserté un par de copias de seguridad notables.
No hubo salida de texto: se utilizó html
Al final de la competencia, quedó claro que no tendría tiempo para transferir la representación del texto al motor. Incluso sin un generador. Había muchas opciones, aquí hay cuatro principales:
- Representación de texto en un lienzo 2D transparente que se encuentra en la parte superior del lienzo con WebGL.
- Haz un juego sin texto
- Hornea las palabras necesarias y úsalas como sprites
- Salida de HUD en html
De acuerdo con los términos de la competencia, era posible usar solo la fuente de píxeles personalizada proporcionada, por lo que se eliminó la primera opción (renderizar texto en un lienzo 2D). El lienzo se puede representar utilizando solo fuentes del sistema. Las fuentes cargadas en CSS a través de fontface funcionan extremadamente inestables.
Jugar sin texto es una excelente y creativa opción. Es una pena que con creatividad en ese momento ya me sintiera mal.
El vocabulario mínimo requerido era grande e infló el tamaño de los activos. Además, la visualización de números todavía requería una cierta lógica.
Y finalmente, llegamos a la muleta real, que utilicé: simplemente implementé el HUD como marcado html debajo del lienzo, conecté @fontface a css y organicé la actualización a través de la API DOM estándar (getElementById).
Reinicio del juego - document.location.reload ()
Cuando un jugador muere, quiere cerrar el juego o comenzarlo de nuevo. Desafortunadamente, si no proporciona algún mecanismo de reinicio desde el principio y difumina todo el estado del juego en un grupo de clases mal organizadas, no obtendrá ningún reinicio agradable. Siempre habrá un lugar mágico que no se ha restablecido a cero.
Una muleta excelente en este caso fue una recarga de página banal a través del encabezado document.location.reload () mencionado en el encabezado. Dado el pequeño tamaño de la compilación final (menos de 300 kb, incluidos todos los recursos) y el hecho de que el juego funciona localmente, la velocidad de reinicio puede descuidarse.
Que paso
Puede probarlo en línea aquí: https://perfectdaemon.imtqy.com/151/index.html
Enlace al repositorio: https://github.com/perfectdaemon/ts-game
La versión del repositorio con el código fuente de este juego: https://github.com/perfectdaemon/ts-game/releases/tag/0.1.0
La conclusión es un final agradable.
En conclusión, me gustaría describir brevemente los pros y los contras subjetivos de escribir juegos en WebGL + TypeScript.
Pros
- Escribe una vez, juega / depura en todas partes. Es genial que pueda poner el juego en imtqy.com, y cualquiera puede jugarlo desde cualquier dispositivo con un navegador. Naturalmente con una serie de reservas.
- Después de ciertas configuraciones y agregar TypeScript, trabajar con JS moderno no es tan malo.
- Conveniente para crear contexto (en comparación con Win API y OpenGL)
- Hay una herramienta conveniente (Visual Studio Code), que está bien equipada con complementos y realmente ayuda a escribir código a través de consejos, fragmentos y notas sobre áreas problemáticas.
Contras
- Javascript se ejecuta en un solo hilo. Y el problema ni siquiera es que desee considerar la física o la lógica en flujos separados. El perfil mostró que las llamadas WebGL están bloqueando, es decir esperan a que regrese el control desde el controlador de la tarjeta de video antes de continuar con la ejecución del código. Aunque la mayoría de las llamadas de WebGL devuelven nada más que nulas. Las implementaciones de escritorio OpenGL (en algunos controladores) para muchas funciones devuelven el control instantáneamente, lo que aumenta significativamente la velocidad de renderizado.
- Un pequeño paso a la izquierda / derecha, y estás completamente solo. ¿Tienes un problema con Angular y Typecript? Los primeros dos enlaces para desbordar la pila te ayudarán. ¿Hubo un deseo de hacer amigos con Typecript por separado y surgió un extraño error / pregunta? Prepárese para el hecho de que bien puede estar solo. Por supuesto, como una persona que anteriormente escribió en la muy popular (no) pila de FreePascal + OpenGL, estoy acostumbrado. Pero en el caso de un lenguaje maduro como C ++, siempre habrá un indio que ya haya resuelto ese problema. Y luego los chinos, que lo resolvieron usando el controlador de Guitar Hero y Arduino.