Introduction
City Wizard Go (http://csjl.teamtop3.com/) is a cocos2d-x-based lbs social game, through the exploration of real maps, discovering and capturing hidden wild Elves, using the game's rich gameplay to enhance and evolve their own elves team, Step by step to become an elf trainer.
The game has been developed in a mix of C + + and LUA programming, with the advantages of high-performance, cross-platform system compatibility for C + +, and Lua's agile and convenient development efficiency. Cocos2d-x provides a complete set of lua-binding tools to help developers implement code Federation for C + + and LUA, which facilitates data communication and code intermodulation between the two. Starting with lua-binding, this paper introduces the details of mixed programming of C + + and Lua, and discusses the possible problems and development. This article was originally published in the blog Park (http://www.cnblogs.com/dabaopku/p/5649294.html), the exclusive authorization XX reprint.
The game development is based on Cocos2d-x 3.2.0 version, other users please read the official documents and source code.
Principle Introduction
Lua (https://www.lua.org/) as a lightweight scripting language, with its simple grammatical structure, convenient C + + integration capabilities, efficient execution efficiency received the majority of game developers love, is also the first Cocos2d-x official introduction of the scripting language.
As a scripting language, Lua executes in a run-time environment (state) that preserves the memory space that the script needs to run, the global variables that are created, the library files that are loaded, and so on. In this runtime environment there is also a stack space, which functions as data transfer and function invocation in Lua and C. Lua native implements a lot of C APIs to manipulate the stack space, allowing developers to easily implement Lua scripting code and C-compiled code in two-way communication.
The topic of this article is LUA and C + + mixed programming, but the back is actually the LUA and C API calls each other, all C + + functionality through a layer of C function packaging, this is to keep in mind, this is the core of lua-binding.
The Lua-bingding tool provided by Cocos2d-x uses Libclang to analyze C + + source code, extract syntax trees, encapsulate C + + class member functions as C functions, and then automatically invoke the LUA C API based on the parameter type, enabling operations on the stack space, passing C + + data to Lua . The LUA script loads the compiled C + + library and is free to invoke class objects and member functions in C + +; C + + code can use the LUA C API directly, execute a LUA script, and get the return result through the stack space.
Operation Combat
In this section we will detail the implementation of C + + and LUA hybrid programming, first of all, if you use Cocos2d-x's tools to automatically export the C + + code in the project as a LUA module, and then introduce the manual export of special types of functions, and finally introduce practical techniques and potential pitfalls.
Automatic generation of LUA modules
The Lua-binding tool provided by Cocos2d-x is located in the project Tools/tolua directory, where you can see genbindings.py, **.ini, Userconf.ini and other files, which are the configuration files for the custom code export policy.
- Userconf.ini: This file configures the environment variables that the system is running, such as the ADK path, and uses the system default values to
- genbindings.py: This is the script that generates the Lua-binding code, and the final Cmd_args parameter of the code configures the different LUA modules that need to be exported, adding entries here as needed. The first parameter in parentheses represents the module name (described below), and the second parameter represents the name of the generated file; If you want to customize the build directory, you can modify the Output_dir variable
- **.ini: Here is the key to the export configuration, we take Cocos2dx.ini as an example, detailing the role of each part
- [Cocos2d-x] here corresponds to the module name described above, to be consistent with the first parameter
- prefix adds a prefix to all generated C functions to prevent naming duplicates
- target_namespace exported Lua module namespaces, important
- Next is a number of compilation parameters for the auxiliary Libclang to find the header file, set the macro parameters, if found clang error, you can consider modifying the parameters here
- headers This parameter can set a set of header files, the program according to the header file and its included header files, extract the C + + declared class, as an export object, important
- Classes This parameter configures a list of patterns based on regular expressions, filters the classes extracted from the previous parameter, and gets the list of classes that are finally exported, which is important
- Skip does not want to export class-level functions to handle some and LUA incompatible C + + parameters, such as Std::function, std::p air, etc., these parameters can not be passed to Lua through the stack space, so there is no way to export to LUA use, need to be ruled out. Important
- rename_functions, rename_classed renaming exported functions and classes is of little use
- classes_have_no_parents, Base_classes_to_skip, abstract_classes Some small functions, not very useful
After setting up this file and running the genbindings.py file, you can see the generated C + + code. By adding this code to the project, you can use the C + + functionality directly in the LUA script.
For example, there is a class in C + +:
Class Guidemanager{public: static Guidemanager *getinstance (); Public: bool IsAvailable (const std::string &id); void AddGuide (const std::string &id); void Finishguide (const std::string &id); BOOL Isguidefinished (const std::string &id); void Clear ();p rotected: std::map<std::string, bool> _finishedguides; Std::mutex _lock;};
By lua-binding the derived class, you can use it directly in the LUA code:
Local manager = pp. Guidemanager:getinstance () If manager:isavailable ("12345") then – Show guide manager:finishguide ("12345") End
With these simple configurations, you can export hundreds of classes and thousands of of member functions directly from the project to use with Lua. While generating C + + files, the program also generates a series of LUA files that are not actually functional, each of which corresponds to an export class that lists all the functions exported by this class and the type of the parameters, so that the developer can verify that the exported method meets the expectations. At the same time can be given to third-party plug-ins to assist the IDE for code highlighting and prompting.
If the developer has updated the C + + code, only need to rerun the script, update the export file.
The above is cocos2d-x recommended for developers to use the lua-binding scheme, can be found on the official website and the network of rich tutorials, this is no longer in-depth expansion.
Manually exporting LUA modules
In practical applications, it is also important to manually export a functional module, such as implementing a network library in C + +, by passing a std::function as the callback function, the function prototype is as follows:
void get (const std::string &path, Json::value ¶ms, std::function<void (Networkresponse *) > callback);
However, the functions in LUA are not compatible with C + + std::function, and cannot be passed directly to C + + using Lua functions, so the lua-binding tool cannot automatically generate code bindings. Developers need to manually implement the transfer of parameters and convert LUA functions to C + + std::function.
To overcome this difficulty, let's take a look at how lua-binding automatically generates code:
int Lua_pocketpet_petmodel_getskillbyid (lua_state* tolua_s) {//1 int argc = 0; Pocketpet::P etmodel* cobj = nullptr; bool OK = true; CObj = (pocketpet::P etmodel*) Tolua_tousertype (tolua_s,1,0);
2 argc = Lua_gettop (tolua_s)-1; if (argc = = 1) { std::string arg0; OK &= luaval_to_std_string (tolua_s, 2,&arg0); if (!ok) return 0;
3 pocketpet::skillmodel* ret = Cobj->getskillbyid (arg0); Object_to_luaval<pocketpet::skillmodel> (tolua_s, "pp. Skillmodel ", (pocketpet::skillmodel*) ret); return 1; }
return 0;}
As we can see, LUA calls the C + + code altogether with 3 steps:
- Get C + + objects
- Get parameters, verify parameter types
- Calling member functions
The auto-generated code supports type int, double, type, pointer type, std::string, Std::map, Std::vector, Cocos2d::map, Cocos2d::vector, and other template types that are beyond these ranges, We need to make it ourselves. Referring to the above code, we can first implement the following function:
int Lua_pocketpet_networkmanager_getinlua (lua_state* tolua_s) { int argc = 0; pocketpet::networkmanager* cobj = nullptr; bool OK = true; CObj = (pocketpet::networkmanager*) tolua_tousertype (tolua_s,1,0); ARGC = Lua_gettop (tolua_s)-1; if (argc = = 3) { std::string arg0; std::string arg1; Lua_function arg2; OK &= luaval_to_std_string (tolua_s, 2,&arg0); OK &= luaval_to_std_string (tolua_s, 3,&ARG1);
1 arg2 = Toluafix_ref_function (tolua_s, 4, 0); if (!ok) return 0; Cobj->get (arg0, arg1, arg2); return 0; } return 0;}
Here, we first obtain a LUA function pointer of type lua_function (that is, int) by toluafix_ref_function, passing this value as an argument to the business function. In the business function, the function pointer is moved back and forth through the stack space as follows:
void Networkmanager::get (const std::string &path, const std::string ¶ms, int callback) { auto func = [call Back] (Networkresponse *response) { Auto engine = Luamanager::getinstance ()->engine (); Engine->getluastack ()->pushobject (response, "pp.networkresponse");
1 engine->getluastack ()->executefunctionbyhandler (callback, 1); }; Json::value JSON; This->get (Path, JSON, func);}
We created a Std::function object func as a wrapper for the LUA function, and within Func, called the LUA callback function through the LUA stack space. With these two tiers of encapsulation, the function of LUA is implemented as a callback function for C + +.
For other special types, it can be solved by similar means.
Other skills and potential risks
Through the lua-binding scheme, it is easy to import C + + development into LUA, which can facilitate the team to transform from C + + to Lua, and improve the speed of rapid iteration update later in the product. While scripting is now encouraged, the application of C + + is unavoidable, such as Channel SDKs, such as cross-platform adaptation, such as account security, and so on, all of which require C + +, the Swiss Army knife, to meet all challenges. In addition to passing data through the stack space between C + + and Lua, there are a number of mechanisms for communication to overcome the limitations of lua-binding.
One option is to create a dedicated memory space through which the temporary objects are stored through a key-value pair, and both parties pass the necessary information through this shared space. This way, it is possible to transfer complex data flexibly, and to deal with the problem of calling C + + asynchronously, preventing Cocos2d-x objects from being autorelease across frames.
Another scenario can use message distribution, through serialization and deserialization of data objects, to implement complex data transfer, such as JSON objects, but need to evaluate the performance loss of the implementation.
When using lua-binding, you also need to consider thread execution issues, and if multiple callbacks and UI refreshes are involved, make sure that the content is updated on the main thread.
In addition, invoking LUA scripts in C + + creates a new runtime environment in which data between different run-time environments is independent of each other, paying particular attention to whether the script file-related initialization work is performed correctly.
Summarize
In this paper, we introduce the basic principles and implementation of mixed programming of C + + and LUA using cocos2d-x tools, and hope to help you.
Play Cocos2d-x lua-binding for C + + and LUA hybrid programming