Muy buenas, les saluda Luis y esta vez les traigo otro post.
Índice
¿Qué es Candy?
El motor Candy fue diseñado y desarrollado por el equipo técnico de Xianyu.
- Es un motor de interacción estable, liviano, fácil de desarrollar y integrado en la aplicación.
- La serie de juegos cumple con los estándares de la industria.
- El sistema de renderizado está altamente integrado con el sistema Flutter. Las escenas del juego se pueden combinar a la perfección con la interfaz de usuario de Flutter.
- El sistema de animación proporciona un fuerte soporte para los formatos convencionales y presenta una fácil extensibilidad.
Este artÃculo explica principalmente por qué y cómo desarrollamos este motor.
Antecedentes
Recientemente, la gamificación de aplicaciones se ha convertido en una nueva tendencia. Aplica algunos métodos de entretenimiento divertidos y atractivos o escenas que se usan en los juegos a otras aplicaciones para mejorar la adherencia del usuario y aumentar los usuarios activos diarios (DAU)
a un costo menor.
Además, en algunos escenarios que requieren orientación del usuario, la gamificación facilita a los usuarios la aceptación y realización de tareas de orientación y anima a los usuarios a permanecer inmersos en las tareas mediante incentivos, formando un cÃrculo virtuoso.
Pensando
Las aplicaciones generalmente usan minijuegos HTML5
integrados, pero presentan algunos peligros ocultos y muchas tiendas de aplicaciones no los recomiendan.
Por lo tanto, necesitábamos encontrar un método nuevo y seguro para desarrollar minijuegos integrados basados ​​en aplicaciones.
QuerÃamos que este método presentara un desarrollo fácil, un rendimiento estable y una funcionalidad completa. Estos tres deseos informaron nuestra búsqueda de un nuevo método.
TenÃamos tres ideas principales sobre los minijuegos integrados basados ​​en aplicaciones:
Actualmente, el ecosistema para el desarrollo de juegos nativos no está muy maduro. Además, el uso del desarrollo nativo requiere dos conjuntos de código en ambos lados, lo que genera costos de desarrollo relativamente altos y costos de mantenimiento posteriores.
Actualmente, los motores de juegos están muy maduros. Sin embargo, generalmente se utilizan para desarrollar juegos intensivos.
El tamaño del motor es relativamente grande y, por lo tanto, la introducción de un motor de juego aumentará significativamente el tamaño del paquete.
Además, debido a la complejidad, se necesita mucho tiempo para poner en marcha los motores, lo que es difÃcil de lograr abriendo las páginas del juego en segundos.
Después de que se carga un motor de juego, el consumo de memoria es muy grande. La comunicación y la interacción entre el motor del juego y la aplicación son relativamente complicadas.
Actualmente, no existe una pila hÃbrida adecuada para admitirlo. Los motores de juegos tienen capacidades de IU débiles y no se pueden usar para la lógica de IU de aplicaciones complejas.
Si se utiliza un motor de juego para desarrollar minijuegos integrados, no puede integrar interfaces de usuario en páginas de minijuegos, como escenas de juegos y feeds.
Flutter en sà es una solución de aplicación entre terminales basada en Skia, un motor de renderizado 2D. Tiene capacidades de renderizado 2D intrÃnsecas.
Por lo tanto, Flutter ofrece un método prometedor para el desarrollo de minijuegos integrados basados ​​en aplicaciones. Actualmente, Flutter tiene algunos motores de juegos ligeros, como Flame.
Flame admite capacidades de animación y lógica de juego simple. Al mismo tiempo, el juego completo finalmente se inserta en una aplicación como un widget. Esto permite una integración perfecta de la parte del juego y la parte de la interfaz de usuario en las páginas del minijuego.
Sobre la base de las consideraciones anteriores, decidimos utilizar un motor de interacción ligero Flutter.
Llama o diseño independiente
El motor Flame
 es un buen motor de minijuegos en el ecosistema Flutter, pero aún tiene los siguientes problemas:
- Sistema de juego incompleto: el motor solo proporciona Juego y Componente. Los conceptos de Scene y GameObject no existen. Como resultado, el anidamiento de los objetos del juego es complejo y no se adapta bien a varias escenas.
- El motor está completamente implementado usando Canvas. La actualización parcial no se admite en escenas de juegos, lo que presenta riesgos de rendimiento.
- Falta de un sistema de GUI: es difÃcil anidar interfaces de usuario en una escena.
- El motor carece de un sistema de eventos por gestos.
- Soporte para formatos de animación no convencionales: la animación esquelética es compatible con Flare. DragonBones no es compatible. La animación de partÃculas se implementó recientemente y es compatible con los formatos convencionales.
- Existen problemas de memoria en la gestión de recursos. Los recursos no se liberan después de que se cargan.
- El motor carece de adaptabilidad al modelo de dispositivo.
Basados ​​en estas preocupaciones, decidimos diseñar un nuevo motor de interacción Flutter.
- Mejoramos el sistema de juego basado en el motor EVA del Grupo Alibaba y el motor Unity en la industria.
- Reutilizamos la actualización parcial de Flutter.
- Reutilizamos la interfaz de usuario de Flutter como interfaz gráfica de usuario.
- Reutilizamos la gestión de gestos de Flutter.
- Implementamos animación esquelética y animación de partÃculas que son compatibles con los formatos convencionales.
- Reutilizamos la biblioteca de recursos de la aplicación (biblioteca de imágenes).
- Implementamos la adaptación global
750
.
Entre los puntos anteriores, 2
a 4
integran esencialmente el sistema de renderizado del motor de interacción en el sistema de renderizado Flutter.
A continuación se presenta el diseño de nuestro motor en orden basado en cómo resuelve los problemas anteriores.
Diseño de motor Candy
Primero, analizamos qué capacidades se requieren para el negocio de la gamificación. Después de analizar nuestras escenas comerciales, obtuvimos las capacidades que se muestran en la Figura 4–1
.
Después de la descomposición, el motor de interacción debe tener un sistema de juego, un sistema de renderizado, un sistema de ciclo de vida, un sistema GUI, un sistema fÃsico, un sistema de animación, un sistema de recursos y un sistema de eventos (gestión de gestos).
De acuerdo con nuestra idea anterior, la renderización de juegos interactivos debe integrarse en el sistema de renderización Flutter.
Basándonos en esta idea, podemos reutilizar el sistema de interfaz de usuario de Flutter y también necesitamos integrar la gestión de gestos del juego y Flutter. Finalmente, obtenemos un marco como se muestra en la Figura 4-2
.
La arquitectura del motor de interacción consta de cuatro partes.
Esto proporciona interfaces de juego expuestas externamente, incluidas interfaces para crear juegos, crear objetos de juego y agregar componentes de juego. También encapsula las interfaces de fábrica para algunos objetos y componentes de juegos de uso común.
El sistema de gestión del mundo del juego gestiona las relaciones organizativas entre Juegos, Escenas, GameObjects y Componentes, controla el inicio y cierre de los subsistemas del juego y el sistema de renderizado.
Esto complementa las capacidades de gamificación con un sistema de ciclo de vida, un sistema fÃsico, un sistema de animación y un sistema de recursos, que son llamados por el sistema de juego.
Este es el responsable del procesamiento del juego. El sistema de renderizado del motor está altamente integrado con la lógica de renderizado de Flutter. Por tanto, es compatible con el sistema GUI y el sistema de eventos (gestión de gestos).
Sistema de juego
Usando el diseño de Unity como punto de referencia, el sistema de juego tiene los siguientes cuatro elementos:
- Juego: clase de juego. Es responsable de la administración general del juego, la administración de carga de escenas y la administración y programación del subsistema.
- Escena: clase de escena de juego. Es responsable de la gestión de cada objeto del juego en las escenas del juego.
- GameObject: clase de objeto de juego. Es la unidad más pequeña de objetos de juego en el mundo del juego. Cualquier objeto en el mundo del juego es un
GameObject
. - Componente: clase de componente del juego. Estos indican los atributos de capacidad de un objeto de juego. Por ejemplo,
SpriteComponent
, el componente de sprite, indica la capacidad de renderizado de sprite.
GameObject
posee diferentes capacidades al combinar varios componentes. Diferentes combinaciones hacen que GameObjects
sea distintivo. La Figura 4–3
muestra las relaciones organizativas de todo el sistema de juego.
Ciclo vital
Basándonos en las caracterÃsticas de Unity
y Flutter
, diseñamos un ciclo de vida con ocho devoluciones de llamada, como se muestra en la Tabla 4–1.
Básicamente, satisface las necesidades del desarrollo empresarial de juegos interactivos.
Sistema de renderizado
Teniendo en cuenta la integración con el sistema de renderizado de Flutter, no podemos usar Canvas para una gestión de renderizado integral de todo el juego.
En su lugar, necesitamos combinar GameObject
con RenderObject
(objeto de renderizado Flutter), como se muestra en la Figura 4-4.
Primero, la cantidad de objetos del juego debe integrarse de manera efectiva con los tres árboles de Flutter. Por lo tanto, cada GameObject
debe corresponder a un Widget, Element y RenderObject.
El proceso de integración ayuda a resolver los siguientes problemas:
- Conversión e integración entre el sistema de coordenadas del diseño Flutter.
- Procesamiento para agregar y eliminar dinámicamente objetos del juego.
- Procesamiento para modificar dinámicamente la profundidad de renderizado del juego.
- Soporte para objetos de juego por Flutter Inspector.
La integración general del renderizado es relativamente compleja y es necesario eliminar muchos BadCases.
Los artÃculos siguientes describirán en detalle el proceso de integración del renderizado del motor de interacción con el sistema de renderizado Flutter. Por lo tanto, no daremos una descripción detallada aquÃ.
Sistema de GUI
El renderizado se ha integrado en el sistema Flutter y cada GameObject
corresponde a un Widget. Por lo tanto, podemos diseñar un GameObject
especial que admita la inserción de un árbol de widgets de Flutter.
Podemos reutilizar la interfaz de usuario de Flutter en lugar de implementar la GUI por separado. Esta lógica es básicamente la misma que para la integración de renderizado.
El árbol de widgets insertado funciona como hijo del widget de GUI. La lógica de diseño, pintura y hitTest
se implementa en GUIRenderObject
.
A continuación, se proporciona un segmento de código de muestra de GUI. El proceso de desarrollo es relativamente sencillo.
final GUIObject gui = IdleFishGame.createGUI( 'gui', child: GestureDetector( child: Container( width: 100.0, height: 60.0, decoration: BoxDecoration( color: const Color(0xFFA9CCE3), borderRadius: const BorderRadius.all( Radius.circular(10.0), ), ), child: const Center( child: Text( 'Flutter UI example', style: TextStyle( fontSize: 14.0, ), ), ), ), behavior: HitTestBehavior.opaque, onTap: () { print('UI is clicked'); }, ), position: Position(100, 100), ); game.scene.addChild(gui);
Sistema de eventos
Sobre la base de la integración del renderizado en el sistema Flutter, hemos integrado el sistema de eventos y agregado el componente de procesamiento de gestos GestureBoxComponent
, como se muestra en la Figura 4-5
:
El proceso de integración es el siguiente:
GestureBoxComponent
registra los métodos de devolución de llamada de gestos registrados por los desarrolladores con el detector de gestos.- El
RenderObject
correspondiente alGameObject
duplica la lógicahitTest
y procesa el clickhitTest
de acuerdo con las especificaciones de Flutter.GestureBoxComponent
determina si se puede consumir un clic. - El
GameObject
duplicahandEvent
para enviar un evento de clic alGestureBoxComponent
para su consumo. - Después de recibir el evento de clic,
GestureBoxComponent
lo envÃa al detector de gestos. - El detector de gestos transmite el clic a la arena de gestos para la competencia de gestos. El gesto ganador se devuelve al detector de gestos y finalmente se devuelve para la respuesta al evento de gesto. Naturalmente, este paso pertenece a la lógica de Flutter.
Otros subsistemas
Actualmente, apoyamos la animación esquelética y la animación de partÃculas. Los recursos admitidos son DragonBones
para la animación esquelética y EgretFeather
para la animación de partÃculas.
Debido a las limitaciones de espacio, la implementación de la animación especÃfica se discutirá en detalle en artÃculos posteriores.
Actualmente, el sistema de recursos del motor de interacción es relativamente simple. Este artÃculo ofrece una breve introducción. El sistema de recursos se diseñó reutilizando el sistema de recursos de la aplicación.
Esto garantiza que la aplicación tenga solo una biblioteca de recursos, lo que reduce la sobrecarga de memoria y aumenta la tasa de reutilización de recursos. La Figura 4–6
muestra la arquitectura del sistema de recursos.
Se agrega una capa de proxy compatible con el sistema de recursos de la aplicación y el sistema de recursos de respaldo entre el sistema de juego y el sistema de recursos.
El sistema de recursos de respaldo se llama automáticamente si el sistema de recursos de la aplicación no está registrado.
El sistema de recursos de respaldo actualmente se divide en dos partes:
- Biblioteca de imágenes de respaldo: reutiliza
Flutter ImageCache
. Esta parte reutiliza las capacidades de Flutter para la gestión de la memoria. - Gestión de recursos JSON de animación: actualmente, solo se implementa la lógica de lectura JSON. La administración de caché no está implementada debido a la baja reutilización de JSON.
El sistema de recursos no tiene capacidades de carga y precarga remotas, que planeamos implementar en el futuro. Los artÃculos posteriores compartirán la implementación del diseño especÃfico.
En el futuro, detallaremos algunos diseños de sistemas especÃficos, como el sistema de renderizado y el sistema de animación, a través de una serie de artÃculos sobre el motor Candy.
Hemos encontrado muchos problemas durante el proceso de diseño e implementación del motor Candy. Por ejemplo, Flutter experimenta una pérdida de memoria durante el proceso de renderizado y la recopilación de memoria no se solicita.
Los artÃculos posteriores detallarán la resolución de problemas y las soluciones a estos problemas y las pruebas y análisis del rendimiento y la estabilidad del motor Candy.
Gracias por leer este post.
Añadir comentario