[Cocos2d-x] How to make Script Binding (Part 1)

Introduction

My name is @tkyaji. This is my first participation in the Advent Calendar. I would like to write an implementation method when adding Script binding to Cocos2d-x. I'm using version 3.2 of Cocos2d-x.

In addition, the preparation required when using bindings-generator was last year's Advent Calendar. giginet wrote a very easy-to-understand article, so I will omit the explanation around that (it was saved) [Cocos2d-x 3.0] How to automate Script Binding with binding-generator

In the following explanation, the script language to be added is described as "Lang". For example, for Lua, replace "Lang" with "Lua".

Rough procedure

  1. Create a LangEngine class that inherits ScriptEngineProtocol
  2. Write a function to convert between C ++ type and Lang language type
  3. Add target language to bindings-generator
  4. With bindings-generator, write the glue code generation logic earnestly
  5. If you can do it all, correspond to the cocos command

It's almost like this. The implementation of the bindings-generator and cocos command is written in Python. It will probably be the last to support the cocos command, so first create a Lua Binding project and I think it is better to implement it in that.

Create LangEngine class

Create an Engine class that corresponds to LuaEngine for Lua and ScriptingCore for JS. It inherits from cocos2d :: ScriptEngineProtocol and overrides the following virtual function.

Returns constants for each scripting language. There is an enum called ccScriptType in ScriptEngineProtocol, so add the kScriptTypeLang constant here and I will return it.

Called by the Ref class destructor. When an instance on C ++ dies due to autorelease etc., the instance on Lang language is also deleted. Implement such processing. The Ref class has fields _ID and _scriptObject. By setting the instance information on the Lang language here, the instance of C ++ and the instance of the Lang language can be set. It can be linked.

Reads and executes the specified Lang language string.

Loads and executes the specified Lang language script file. Basically, this method executes the script file under the * src * directory, so This is the method that needs to be implemented first.

executeGlobalFunction

Executes a global function on the Lang language with the specified name.

sendEvent

Called when various events (menu button press, touch, schedule, etc.) are fired. The argument ScriptEvent determines the type of event. If the event is registered by a method different from C ++, the process registered in this method is called. For example, in Lua, the callback is registered with the method registerScriptTapHandler, so In this case, execute the Lua function registered with registerScriptTapHandler in sendEvent. Conversely, if you have registered an event in ʻEventDispatcheras in C ++, Implementation is not required forsendEvent`.

handleAssert

Called from CCASERT. Here, we will implement error log output and Lang language error handling. For example, raise an exception on the Lang language.

parseConfig

For cooperation with CocoStudio?

Implemented type conversion function between C ++ ⇔ Lang language

The source is LuaBasicConversions for Lua and js_manual_conversions for JS. We will create a function that converts C ++ types and Lang language types. For example, in the case of Lua, the function that converts Vec2 is defined as follows.

// c++ -> lua
void vec2_to_luaval(lua_State* L,const cocos2d::Vec2& vec2)
{
    if (NULL  == L)
        return;
    lua_newtable(L);                                    /* L: table */
    lua_pushstring(L, "x");                             /* L: table key */
    lua_pushnumber(L, (lua_Number) vec2.x);               /* L: table key value*/
    lua_rawset(L, -3);                                  /* table[key] = value, L: table */
    lua_pushstring(L, "y");                             /* L: table key */
    lua_pushnumber(L, (lua_Number) vec2.y);               /* L: table key value*/
    lua_rawset(L, -3);
}

// lua -> c++
bool luaval_to_vec2(lua_State* L,int lo,cocos2d::Vec2* outValue)
{
    if (nullptr == L || nullptr == outValue)
        return false;
    
    bool ok = true;
    
    tolua_Error tolua_err;
    if (!tolua_istable(L, lo, 0, &tolua_err) )
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err);
#endif
        ok = false;
    }
    
    if (ok)
    {
        lua_pushstring(L, "x");
        lua_gettable(L, lo);
        outValue->x = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1);
        lua_pop(L, 1);
        
        lua_pushstring(L, "y");
        lua_gettable(L, lo);
        outValue->y = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1);
        lua_pop(L, 1);
    }
    return ok;
}

These conversion functions are used when implementing bindings-generator. You don't have to create everything first, as you can add the types you need as needed while implementing the bindings-generator. It is also possible to implement the above conversion function without creating it, but in most cases it is easier to create it.

For the time being, that's all for today. Tomorrow I would like to explain about the implementation of * bindings-generator *.

[Cocos2d-x] How to make Script Binding (Part 2)

Recommended Posts

[Cocos2d-x] How to make Script Binding (Part 2)
[Cocos2d-x] How to make Script Binding (Part 1)
[Cocos2d-x 3.0] How to automate Script Binding with binding-generator
How to make a shooting game with toio (Part 1)
How to make unit tests Part.2 Class design for tests
How to make a hacking lab-Kali Linux (2020.1) VirtualBox 64-bit Part 2-
How to make a Japanese-English translation
How to make a slack bot
How to make a crawler --Advanced
How to make a recursive function
How to make a deadman's switch
[Blender] How to make a Blender plugin
How to make a crawler --Basic
How to authenticate with Django Part 2
How to authenticate with Django Part 3
How to make a unit test Part.1 Design pattern for introduction
How to make Word Cloud characters monochromatic
[Blender] How to set shape_key with script
How to make Selenium as light as possible
How to use cybozu.com developer network (Part 2)
How to use Tweepy ~ Part 1 ~ [Getting Tweet]
[Ubuntu] How to execute a shell script
How to make multi-boot USB (Windows 10 compatible)
How to make a Backtrader custom indicator
How to make a Pelican site map
How to run a Maya Python script
How to make an embedded Linux device driver (11)
How to make WTForms TextArea correspond to file drop
How to make Spigot plugin (for Java beginners)
How to make an embedded Linux device driver (1)
How to make an embedded Linux device driver (4)
How to make multiple kernels selectable on Jupyter
How to make an embedded Linux device driver (7)
How to run some script regularly in Django
How to make scrapy JSON output into Japanese
How to make an embedded Linux device driver (3)
How to use Tweepy ~ Part 2 ~ [Follow, like, etc.]
How to make a QGIS plugin (package generation)
How to measure execution time with Python Part 1
I read "How to make a hacking lab"
[Blender x Python] How to make an animation
How to make an embedded Linux device driver (6)
How to make Substance Painter Python plugin (Introduction)
[Blender x Python] How to make vertex animation
How to make an embedded Linux device driver (5)
How to make an embedded Linux device driver (10)
How to make Python faster for beginners [numpy]
How to make Python Interpreter changes in Pycharm
How to make Linux compatible with Japanese keyboard
How to make an embedded Linux device driver (9)
Inspired by "How to make pure functional JavaScript"
How to measure execution time with Python Part 2
How to make AWS rekognition recognize local image files
How to add help to HDA (with Python script bonus)
[Continued] Inspired by "How to make pure functional JavaScript"
How to make Yubico Yubikey recognized in Manjaro Linux
Explain in detail how to make sounds with python
How to upload with Heroku, Flask, Python, Git (Part 3)
How to make an interactive CLI tool in Golang
How to upload with Heroku, Flask, Python, Git (Part 1)
How to make a Python package using VS Code