In my
first article on Habré, devoted to the development of a browser game, I showed the main stages of creating the base scene for Blend4Web. A couple of primitives, several textures plus the built-in capabilities of the platform made it possible to easily embody the conceived idea - water with refraction and caustics.
One may admire the modulations on the seabed. The time has come for real work. First of all, you need to understand programming and take the first steps in writing code.
It just so happens that I write code for games exclusively in C #, and JavaScript is not very familiar to me. But learning another programming language is a simple task. Experience with Unity allowed me to create the basic architectural blanks that migrate from project to project, which allows you to deploy the core backbone of the new application in just 15 minutes.
Already traditionally, I divide the game project into several scenes:
- The App contains global objects for controlling gameplay, advertising, social functions.
- Splash is a buffer level where I usually show the process of loading game data, download ads or connect to social services.
- MainMenu - the main menu of the program.
- Level1x - current game level without GUI.
- GameGUI is the actual game GUI loaded by the current level.
Such a scheme allows independently adjusting each block of the game: add new levels, perform interface translations, connect social functions. Basically, communication between the blocks is built on events.
')
Of course, I would like to use something similar for a new game. But you need to consider the possibility of JavaScript and features work with Blend4Web. As it turned out, much of the programming experience for Unity was unacceptable for Blend4Web. Now about everything in order.
The Blend4Web platform is designed for developing WebGL applications. Accordingly, you need to create a small wrapper in HTML. A typical code looks like this:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script type="text/javascript" src="b4w.full.min.js"></script> <script type="text/javascript" src="js/game_app.js"></script> <style> body { margin: 0; padding: 0; overflow: hidden; } #canvas3d { position: absolute; width: 1024px; height: 768px; overflow: hidden; } </style> </head> <body> <div id="canvas3d"></div> </body> </html>
Taking the standard example from the framework documentation, I added a restriction on resolution from myself, since resizing the window involved showing unnecessary areas of the scene. The new version 15.07 has the option force_container_ratio, which should be responsible for maintaining the proportions for different types of displays. But she didn’t really work for me, so I went back to the hard limiters.
Interestingly, the developers offer two versions of the compiled engine: b4w.min.js and b4w.full.min.js. By the name it is clear that the first file is a light version. It’s just not clear what was removed from it (I couldn’t find the information in the help), so I decided to use b4w.full.min.js. By the way, to work with physics you need to connect another file uranium.js.
Take a look at the line script type = "text / javascript" src = "js / game_app.js". It declares a file game_app.js - this is the main script for managing the game. I have already shown in the past articles the simplest programming examples for Blend4Web. But I would like to squeeze out of game_app.js more than simple engine initialization. Here I am going to concentrate all the global functions of the game.
Programming itself begins with the registration of its module in the space b4w. The app module is already present here. That is why I decided to add the “game_” prefix to the name of my scripts in order not to have any further problems.
"use strict" b4w.register("game_app", function(exports, require) { var m_app = b4w.require("app"); var m_data = b4w.require("data"); var m_main = require("main"); exports.init = function() { m_app.init({ canvas_container_id: "canvas3d", callback: init_cb, physics_enabled: false, autoresize: true }); }
This is the first stage - where a new game_app module is registered and the engine initialization function is described:
- canvas_container_id - the name of the output container should be the same as in HTML.
- callback - a function that will be called after the initialization.
- physics_enabled - using physics. While I do not need it in the game, so I set it to false. Note that the activation of physics requires connecting to the project file uranium.js.
- autoresize is an option that forces the engine to automatically resize the screen in accordance with the browser window. In my case, it is useless, but if you open the canvas to the full page, you cannot do without it.
After the engine initialization, the function init_cb is called, which in turn loads the scene from the main menu of the game.
I want to stop using GUI. It is not in Blend4Web. It is annoying at first, but there are two ways to solve the problem.
The first option offered by the framework developers themselves is to use the capabilities of plain HTML. In general, all the official lessons prove that it works, but I prefer my own version - Blender. No problem creating a scene with buttons and handlers. This decision may be wrong and you will have to return to HTML, but for now let it remain as it is.
It is necessary to take into account one more nuance when loading the scene with the data.load function. As I understand it - this is the only option that is in the API and is very peculiar.
m_data.load("mainmenu.json"); m_data.load("scene.json");
What do you think will happen when these two lines of code are executed? If you think that replacing one scene with another, you are mistaken. In fact, scene.json elements will be added to mainmenu.json. The data.load function does not destroy the previous scene, but loads a new one into it. This approach allows you to dynamically load objects, which is very important when developing a web application, and additional function parameters help to manage this process (see the
help ).
Therefore, to replace one scene with another - you need to destroy the previous one. For this there is a command data.unload (id). As the ID, you can specify the sequence number that the scenes receive during loading. For example, a primitive replacement code may be as follows:
data.load("mainmenu.json"); data.unload (); data.load("scene.json");
But the question is, does the load function work with the cache or does it constantly load data from the network?
One more thing that interested me at this stage is how to make a “download bar”. It puzzled me so much that I rummaged through the official forum and was about to ask this question to the developers, but fortunately did not have time. Everything turned out to be very simple and there are corresponding functions in the SDK help. Therefore, the banal conclusion - see the documentation!
The developers offer a special module, which is called preloader. There are ready-made functions for creating the most diverse “stripes”. Notice, not banal transfer of percent of loading of the file, but full-fledged, already visual decisions. But so far I have decided not to bother and chose the easiest option.
This is an example of how to create a “download bar” with Blend4Web:
var m_preloader = require("preloader");
So, the main menu is loaded, the user clicks the “Start” button and goes into the game. This chain and need to create.
In my work, I always follow the simple rule - do not mix actions from different blocks in one “bottle”. One script provides overall control of the application, the other is responsible for the GUI, the third for social functions, etc. This approach allows you to quickly find errors or perform an upgrade program. I want to use the same thing when programming a game for WebGL. Therefore, the processing functions of the main menu should be in a separate file.
It turned out that this is easy. The principle is the same as when creating the first script.
b4w.register("game_mainmenu", function(exports, require) { var m_mouse = require("mouse"); var m_scenes = require("scenes"); var mg_app = require("game_app"); exports.mainmenu_cb = function() { addEventListener("mousedown", main_canvas_down); m_mouse.enable_mouse_hover_outline(); } function main_canvas_down(e) { var x = m_mouse.get_coords_x(e); var y = m_mouse.get_coords_y(e); var obj = m_scenes.pick_object(x, y); var obj_name = m_scenes.get_object_name(obj); if (obj_name == "btStart") { m_mouse.disable_mouse_hover_outline(); mg_app.loadScene(); } } });
This is the complete code. Its task is to determine the mouse click on the button object in the menu and start loading the game level.
First, let's consider the relationship of both scripts. Pay attention to the piece of code from the game_app file:
function loadMainMenu() { var p_cb = preloader_cb; m_data.load("mainmenu.json", m_mainmenu.mainmenu_cb,p_cb,true); }
So loadMainMenu is trying to load a scene with a button. When this process is complete, m_mainmenu.mainmenu_cb will be started. Only in this case the implementation of this function is in another module, which becomes available after its connection in the header:
var m_mainmenu = require("game_mainmenu");
The scene is loaded and control passes to the function of another game_mainmenu script:
exports.mainmenu_cb = function() { addEventListener("mousedown", main_canvas_down); m_mouse.enable_mouse_hover_outline(); }
Blend4Web offers its own event model. The script subscribes to a specific event that generates the engine. In my case, this is a mouse click on the canvas. In the function shown earlier two commands:
- addEventListener () - subscription to the event;
- m_mouse.enable_mouse_hover_outline () - selection of an object when the cursor is over it.
Blend4Web has presets for selecting objects in the scene. Setup is done directly in Blender. In the Object panel you need to enable the Selectable and Enable Outlining options for the primitive (see figure). In addition, you can adjust the thickness and color of the frame, as well as its flickering in the Render panel. Now, when the cursor passes over such an object, it will be marked with an outline.

Go ahead. The player clicked the mouse within the working container. The “mousedown” event is generated and the main_canvas_down function is executed:
function main_canvas_down(e) {
As you can see, the game_mainmenu script only provides the main menu. The level loading itself is performed in the game_app script (call mg_app.loadScene ()), i.e. I managed to correctly set the scripts for the intended functionality.
findings
Programming turned out to be quite easy. I managed to partially reproduce my application workflow in Unity and for Blend4Web: to divide scenes by meaning, to determine the functionality of scripts. In some cases, Blend4Web presented pleasant surprises - this is a ready preloader and edging of objects in the scene (I confess, you need to create the same for Unity yourself). The only thing that did not like is the lack of small examples. I think my whining on this topic has already become familiar, but it really slowed down the process.
Maybe it is worth creating something like a wiki with examples and let the users fill it in? Hey, developers! I am personally ready to give a couple of examples.
Test buildSources