Barbar Q – Learn The Ins and Outs Of Multiplayer HTML5 Development From An Experienced Developer

2019.8.1 Interviews by COCOS

“Barbar Q” is an overhead battle royale game developed by the Hangzhou Electric Soul Studio. The game is multiplayer, with a fun and unique gameplay style. The game did well as an app and the development team, guided by market demand and user comments, wanted to improve their revolutionizing gameplay and technology. Based on their research, “Barbar Q HTML5” was built. Based on the team’s experience in developing competitive products for years, combined with the lightweight characteristics of HTML5, We believe that “Barbar Q HTML5” Can achieve some good results.

We asked “Blueprint,” a developer for the game, to share with us some of the challenges he found when building the game.

Overview

“Barbar Q HTML5” is a real-time competitive battle royale game played on WeChat. When the battle begins, (WebSocket), frame synchronization mode is adopted. The server-side packages forward the player’s frame protocol, and the client receives and processes the battle logic.

Development

Tools

Client: Cocos Creator, JavaScript

Server: Java, C++, Runtime Environment Linux

Third-party libraries: Protobuf C++ version 2.6.1, JS version 6.8.4

Architecture

Here’s a simple diagram of the Architecture:

The client needs to upload the code to the WeChat server and assets from a CDN. The reason why is If our game package and the resources were within 4 MB, then a CDN is not needed. Our game resource package, however, was far more than 4M, so the code is placed on the WeChat server, and the resources were placed on the CDN.

The server is divided into two pieces:

One is a logical server (LogicServer), which is responsible for the interactions of the external system. And a frame synchronization server (RaceServer) that is responsible for data forwarding throughout the battle.

When you open the game from WeChat, we will retrieve the player’s information from their WeChat account first, then go to the logical server for secondary verification. After that verification, we enter the LogicServer, get the corresponding data information in the game, such as the player’s level, backpack information, and so on.

When the player clicks to start the battle, the client connects to the RaceServer.

Development process

When we started the project, due to the lack of resources (only a 2-person team), we basically used the same resources we used with the mobile app. The good thing is that the app was developed in Cocos2d-x. So the UI can be converted to a format supported by Cocos Creator by using an in-house tool. The animation is a Cocos2d-x animation editor, so it couldn’t be converted. The previous art team didn’t participate in the development. So, to reduce the workload, we asked for the help of the Cocos team. Our development tool needed to convert 2d-x format animations into a format supported by Creator. We contacted Cocos and thanks to their Cocos Creator developer Knox, we had an animation converter that helped us a lot and has saved us a lot of work.

If you would like the animation converter, you can download here (Chinese): https://github.com/knoxHuang/cstudio-anim-import


After we transferred the originals with the transfer tool, we discovered it does not support the JSON format, so we contacted Cocos, and they helped us implement the JSON format in the transfer tool.

The tools were completed, and we started coding the game. After working overtime for a month or so to complete a single-player demo, you can start to see the AI working and you can slash each other in the scene. One of the biggest problems encountered in this process was a JavaScript Reference question. Such as:

         var obj = {x:0, y:0};

         var obj2 = obj;

The intention is to copy an object, but the object assignment in JavaScript is a reference, so the operation obj2 will cause the data in the obj object to change, which is not the same as C++, It was complicated, but we were able to complete the task.

Networking the game was our next step. The network adopts WebSocket. The WeChat platform mandates wss. Due to encryption and decryption, the network delay increased. The protocol part adopts protobufjs, and PB passes binary transmission, which is smaller than JSON traffic. The 6.8.4. version of the WeChat platform does not allow for eval. So its new Function dynamic code execution for the poto file doesn’t work. We can only convert to static JavaScript code from the .poto file in advance (version 5.0 was able to load the poto file, but the efficiency is not better than the 6.8 version). Note that the protobufjs default does not support 64-bit integers. If you need to change it, you had to package the long.js file.


Receiving messages

Sending messages

Next, we had network synchronization selected at frame synchronization.

Advantages of frame synchronization:

1. The network traffic is small, so we only needed to forward the player operation instructions

2. The server will perform better by using frame sync tech because it’s light weight supports a large quantity of concurrent visit by users.

Disadvantages frame synchronization:

1. Cheating is easier because the logic is on the client-side, and local data can be modified.

2. The reconnection process needs to run the previous logic. If the single session is too long, it takes a certain time to catch up to the current frame.

Frame synchronization requires the client to execute specific instructions. The client part is divided into three parts:

1. Client rendering part

2. Network part

3. Logical part

Here is a brief description of the logical structure:


The logical structure is mainly composed of skills (the skills here are not the skills released by the character, but could be understood as the interface provided for the actions that are called) and the action (the specific execution interface, such as creating units, modifying coordinates, playing sound effects, moving, delaying execution, etc.) The interface is what’s doing the magic, the program mainly implements various interfaces through a matching table we created. The table can control multiple parameters, add various skills, skill call actions, and actions that are nested in skills, creating flexible game logic.

The effect here is to call the corresponding action

There are two lines in the picture:

Blue stands for stand-alone action. The client needs to send the instruction to the instruction queue. The logic takes the corresponding instruction execution logic from the instruction queue and then executes the results triggered to the client through the event trigger. The client executes according to the logical result, for example. Adding a player to the logic will creates a player model in the client.

Green represents online actions. The network needs to send the player’s operation instructions to the server. After receiving the command, the server saves the instructions to the server current-game queue (used for rolling or viewing), then broadcasts and forwards it to others and the client receives packages coming from the network and are sent to the instruction queue.

Frame synchronization can’t use the system’s random function. You need to encapsulate a random algorithm and specify random seeds to ensure that each device has the same number of random numbers under the same amount of frames.

“Barbar Q HTML5” uses the box2d physical library in the logic, mainly to recognize the functions of movement, collision and other functions of the character. Here, some small changes to the mathematical functions of the box2d library that we made to prevent synchronization error and improve synchronization efficiency.

After another month of development and system debugging, the networking issues were completed, and two people can play a game against each other. During this process, I also encountered a lot of problems.The biggest problems happened when I am out of sync. The sequence of instructions the network received can lead us to go out of synchronization. Luckily we found a solution. JavaScript is invaluable for this. It’s more convenient for us to use JavaScript in this situation as C++ variables are not initialized, so they will be out of sync. JavaScript is initialized, all are undefined, all the same, so they will never be out of sync.

After solving that issue, there seems to be no problems, and we were able to battle without syncing issues. Everything is normal on the PC and I also tried it with iPhone 7, and I ran it with no problems. I tested it with an Android phone and found that the problem was severe. I also used Xiaomi 5s 821 to test, and the frame loses was so bad, it looks like a slide show. So it can be seen that the performance between iOS and Android apps and HTML5 is very different.

Optimization

Our team made PC games before and have no experience in HTML5. So we consulted the Cocos team, and they gave us some great suggestions. At that time, the highest drawcall in the single-game was around 180. We optimized the following points:

1. The original resources are all individual sprites. The character part exported as atlas 1024 by our designers, and Auto Atlas that comes with the Creator helped us out in the UI part.

2. Fixed symbols using BMFont. Letters, numbers and some fixed symbols appearing in a single game were also replaced with BMFont.

3. Node pool, the client-side units have taken the node pool to avoid duplicate creation of nodes, it is said that cc.instantiate has a high overhead in Wechat.

4. Reduce some effects, remove some colors, strokes, dynamic shadow, and other effects used by the shader.

5. Reduce the UI refresh rate, such as the leaderboard in a single game. It turns out that it refreshes every frame. In fact, it is not necessary. It can be refreshed every second instead. There are many similar frames that can be optimized. Prior to Creator v2.0.9, if the units are too many, changing zIndex of the node had a high overhead, and it is also can be changed to 1 second.

6. Optimization of the logic. This is the most significant bottleneck as the configuration file of the app is used at all times, we optimize the table, reduce unnecessary calls. The logic was a bit complicated. When adding the skills in the logic (not the real skills, as explained above), before the optimization, you should perform about 2000 skills per second. Through negotiation and planning with designers, and through various optimizations, we finally reduce the skills to 170 or so.

7. The more frequent object creation in logic using the original cc.Class by all objects were finally built as native JavaScript objects.

8. Reduce the scene objects.

9. Render according to the screen size, the off-screen unit setting node activation is false.

After various optimizations, our drawcall is finally optimized to less than 100. It can run very smoothly on some devices using Android, but it is still a bit stuck on some devices with lower specs.

During our production, Cocos Creator 2.0 was born. After transferring our game to the new version, performance has dramatically been improved. We built an internal release. After testing, the performance improvements were really significant. It was running on a Xiaomi 2s at 10 frames at first. With 2.0., we were running above 28 frames.

I am very grateful to the Cocos official technical team for their help in the development process, giving technical support, and helping us solve problems quickly.

If you want to give the game a try, scan this QR code inside WeChat. Note that this game is for Chinese players, so lag may be an issue for international players.

Cocos is very grateful for the post-mortem brought to us by blueprint, and we wish that “Barbar Q HTML5” can achieve excellent results. We also hope that more and more developers will be able to create more hypercasual games through Cocos Creator. If you encounter any technical problems during use, please feel free to ask your questions in our official forums.