Candy for You: Design of A Flutter Interaction Engine

Best practice of Flutter from Alibaba’s Xianyu tech team

Image for post
Image for post

What Is Candy?

The Candy engine was designed and developed by the Xianyu technical team.

  • It is an app-embedded, lightweight, easy-to-develop, and stable interaction engine.

This article mainly explains why and how we developed this engine.

Background

Recently, app gamification has emerged as a new trend. It applies some fun and enticing entertainment methods or scenes used in games to other apps to improve user stickiness and increase daily active users (DAU) at a lower cost. In addition, in some scenes that require user guidance, gamification makes it easier for users to accept and complete guidance tasks and encourages users to remain immersed in tasks by means of incentives, forming a virtuous circle.

Apps generally use embedded HTML5 mini-games, but these present some hidden dangers and are not recommended by many app stores. Therefore, we needed to find a new and safe method to develop app-based embedded mini-games. We wanted this method will feature easy development, stable performance, and complete functionality. These three desires informed our search for a new method.

Thinking

We had three main ideas about app-based embedded mini-games:

  • Using the native game capabilities

Currently, the ecosystem for native game development is not very mature. Moreover, using Native development requires two sets of code on both sides, incurring relatively high development costs and subsequent maintenance costs.

  • Using game engines, such as Cocos2d-x and Unity

Currently, game engines are very mature. However, they are generally used to develop intensive games. The engine size is relatively large, and therefore introducing a game engine will significantly increase the package size. In addition, due to complexity, it takes a lot of time to start the engines, difficult to achieve opening game pages in seconds. After a game engine is loaded, the memory consumption is very large. Communication and interaction between the game engine and app are relatively complicated. Currently, there is no proper hybrid stack to support it. Game engines have weak UI capabilities and cannot be used for complex app UI logic. If a game engine is used to develop embedded mini-games, it cannot integrate UIs on mini-game pages, such as game scenes and feeds.

  • Using the Flutter lightweight interaction engine

Flutter itself is a cross-terminal app solution based on Skia, a 2D rendering engine. It has intrinsic 2D rendering capabilities. Therefore, Flutter offers a promising method for the development of app-based embedded mini-games. Currently, Flutter has some lightweight game engines, such as Flame. Flame supports simple game logic and animation capabilities. At the same time, the entire game is ultimately inserted into an app as a widget. This allows seamless integration of the game part and the UI part on mini-game pages.

Based on the above considerations, we decide to use a Flutter lightweight interaction engine.

Flame or Independent Design

The Flame engine is a good mini-game engine in the Flutter ecosystem, but still has the following problems:

  1. Incomplete game system: The engine provides only Game and Component. Scene and GameObject concepts do not exist. As a result, the nesting of game objects is complex and not well-suited to multiple scenes.

Based on these concerns, we decide to design a new Flutter interaction engine.

  1. We improved the game system based on the EVA engine of the Alibaba Group and the Unity engine in the industry.

Among the preceding points, 2 to 4 essentially integrate the rendering system of the interaction engine into the Flutter rendering system. The following introduces our engine design in order based on how it solves the preceding problems.

Candy Engine Design

Framework Design

First, we analyze what capabilities are required for the gamification business. After analyzing our business scenes, we obtained the capabilities shown in Figure 4–1.

Image for post
Image for post

After decomposition, the interaction engine needs to have a game system, rendering system, lifecycle system, GUI system, physical system, animation system, resource system, and event system (gesture management).

According to our previous idea, interactive game rendering needs to be integrated into the Flutter rendering system. Based on this idea, we can reuse the Flutter UI system and also need to integrate the gesture management of the game and Flutter. Finally, we obtain a framework as shown in Figure 4–2.

Image for post
Image for post

The interaction engine architecture consists of four parts.

  • Interface layer

This provides externally exposed game interfaces, including interfaces for creating games, creating game objects, and adding game components. It also encapsulates factory interfaces for some commonly used game objects and game components.

  • Game system

The game world management system manages organizational relationships among Games, Scenes, GameObjects, and Components and controls the startup and shutdown of the game subsystems and rendering system.

  • Game subsystem

This supplements gamification capabilities with a lifecycle system, physical system, animation system, and resource system, which are called by the game system.

  • Rendering system

This is responsible for game rendering. The rendering system of the engine is highly integrated with the Flutter rendering logic. Therefore, it is compatible with the GUI system and event system (gesture management).

Game System

Using the Unity design as a benchmark, the game system has the following four elements:

  1. Game: game class. It is responsible for overall game management, Scene loading management, and subsystem management and scheduling.

A GameObject possesses different capabilities by combining various Components. Different combinations make GameObjects distinctive. Figure 4–3 shows the organizational relationships of the entire game system.

Image for post
Image for post

Lifecycle

Based on Unity and Flutter features, we designed a lifecycle with eight callbacks, as listed in Table 4–1. It basically meets the needs of interactive game business development.

Image for post
Image for post

Rendering System

Considering the integration with the Flutter rendering system, we cannot use Canvas for comprehensive rendering management of the entire game. Instead, we need to combine GameObject with RenderObject (Flutter render object), as shown in Figure 4–4.

Image for post
Image for post

First, the number of game objects must be effectively integrated with the three trees of Flutter. Therefore, each GameObject must correspond to a Widget, Element, and RenderObject.

The integration process helps solve the following problems:

  1. Conversion and integration between the coordinate system of the Flutter layout

The overall rendering integration is relatively complex and many BadCases need to be eliminated. Subsequent articles will describe the process of integrating the interaction engine rendering with the Flutter rendering system in detail. Therefore, we will not give a detailed description here.

GUI System

Rendering has been integrated into the Flutter system, and each GameObject corresponds to a Widget. Therefore, we can design a special GameObject that supports the insertion of a Flutter Widget tree. We can reuse the Flutter UI instead of implementing the GUI separately. This logic is basically the same as for rendering integration. The inserted Widget tree operates as the child of the GUI Widget. The layout, paint, and hitTest logic is implemented in GUIRenderObject.

The following provides a segment of GUI sample code. The development process is relatively simple.

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

Event System

On the basis of integrating rendering into the Flutter system, we have integrated the event system and added the gesture processing component GestureBoxComponent, as shown in Figure 4–5:

Image for post
Image for post

The integration process is as follows:

  1. GestureBoxComponent registers gesture callback methods registered by the developers with the gesture detector.

Other Subsystems

Animation System

Currently, we support skeletal animation and particle animation. The supported resources are DragonBones for skeletal animation and EgretFeather for particle animation. Due to space constraints, the specific animation implementation will be discussed in detail in subsequent articles.

Resource System

Currently, the resource system of the interaction engine is relatively simple. This article gives a brief introduction. The resource system was designed by reusing the app resource system. This ensures that the app has only one resource library, reducing memory overhead and increasing the resource reuse rate. Figure 4–6 shows the resource system architecture. A proxy layer compatible with the app resource system and backup resource system is added between the game system and resource system. The backup resource system is automatically called if the app resource system is not registered.

The backup resource system is currently divided into two parts:

Backup image library: reuses Flutter ImageCache. This part reuses Flutter capabilities for memory management.

Animation JSON resource management: Currently, only the JSON read logic is implemented. Cache management is not implemented due to low JSON reusability.

Image for post
Image for post

The resource system does not have remote loading and preloading capabilities, which we plan to implement in the future. Later articles will share the specific design implementation.

Conclusion

This article describes the design of the Candy interaction engine, and also analyzes and introduces the ongoing Flutter interaction engine design from a global perspective. In the future, we will detail some specific system designs, such as the rendering system and animation system, through a series of articles about the Candy engine.

We have encountered many problems during the design and implementation process of the Candy engine. For example, Flutter experiences some memory leakage during the rendering process and memory collection is not prompt. Later articles will detail the troubleshooting and solutions to these problems and the testing and analysis of the Candy engine’s performance and stability, so stay tuned.

(Original article by Chen Xuwei陈绪伟)

Alibaba Tech

First hand and in-depth information about Alibaba’s latest technology → Facebook: “Alibaba Tech”. Twitter: “AlibabaTech”.

Written by

First-hand & in-depth information about Alibaba's tech innovation in Artificial Intelligence, Big Data & Computer Engineering. Follow us on Facebook!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store