• 调用lua函数executeGlobalFunction


    闲来无事,搞了搞cocos2dx的lua脚本,话说lua这东西几年前学过一段时间,也自己开发过c++接口,做过一些小东西,不过时间久远,记忆模糊。捡起来还是费了点功夫,下面就是我的一些体会。


    cocos2dx使用的是tolua++来制作的lua接口,tolua++文档不多,网上的一些文章也是答非所问,所以自己看代码是最佳学习途径。


    cocos2dx操作lua的类是CCLuaEngine,其中实现了加载与实行lua脚本,以及操作lua stack。


    LuaCocos2d.cpp很主要,文件的开头注释也说明其是由tolua++自动生成的,我们想在lua中操作自己定义的类就是通过修改此文件实现的,两个重要函数是void tolua_reg_types (lua_State* tolua_S)与int tolua_Cocos2d_open (lua_State* tolua_S),前者是注册自定义类型,后者是定义其接口,调用关系是tolua_Cocos2d_open调用tolua_reg_types,而tolua_Cocos2d_open是在CCLuaEngine的init中调用的。


    假设我要向lua注册新类,那么首先我要在tolua_reg_types中添加一行注册代码,然后在tolua_Cocos2d_open添加其接口说明,我将这两个步骤定义成两个函数,单独在一个文件中实现,文件名为cwLuaReg.cpp,内容为:
    #include "cwLuaReg.h"


    #include "cwGameObject.h"
    #include "cwCollisionObject.h"
    #include "cwGravityObject.h"


    #ifdef __cplusplus


    static int tolua_collect_cwGameObject(lua_State* tolua_S)
    {
        cwGameObject* self = (cwGameObject*) tolua_tousertype(tolua_S,1,0);
        delete self;
        return 0;
    }


    static int tolua_collect_cwGravityObject(lua_State* tolua_S)
    {
        cwGravityObject* self = (cwGravityObject*) tolua_tousertype(tolua_S,1,0);
        delete self;
        return 0;
    }


    #ifndef TOLUA_DISABLE_tolua_cw_GameObject_create00
    static int tolua_cw_GameObject_create00(lua_State* tolua_S)
    {
        tolua_Error tolua_err;
        if(!tolua_isusertable(tolua_S,1,"cwGameObject",0,&tolua_err) ||
            !tolua_isnoobj(tolua_S,2,&tolua_err))
            goto tolua_lerror;
        else
        {
            {
                cwGameObject* tolua_ret = (cwGameObject*)  cwGameObject::create();
                int nID = (tolua_ret) ? (int)tolua_ret->m_uID : -1;
                int* pLuaID = (tolua_ret) ? &tolua_ret->m_nLuaID : NULL;
                toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret,"cwGameObject");
            }
        }
        return 1;
    tolua_lerror:
        return 0;
    }
    #endif //#ifndef TOLUA_DISABLE


    #ifndef TOLUA_DISABLE_tolua_cw_GameObject_getSpeed00
    static int tolua_cw_GameObject_getSpeed00(lua_State* tolua_S)
    {
    #ifndef TOLUA_RELEASE
        tolua_Error tolua_err;
        if (!tolua_isusertype(tolua_S,1,"cwGameObject",0,&tolua_err) ||
            !tolua_isnoobj(tolua_S,2,&tolua_err))
            goto tolua_lerror;
        else
    #endif
        {
            cwGameObject* self = (cwGameObject*)  tolua_tousertype(tolua_S,1,0);
    #ifndef TOLUA_RELEASE
            if (!self) tolua_error(tolua_S,"invalid 'self' in function 'speed'", NULL);
    #endif
            {
                float tolua_ret = (float)  self->speed();
                tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
            }
        }
        return 1;
    #ifndef TOLUA_RELEASE
        tolua_lerror:
        tolua_error(tolua_S,"#ferror in function 'speed'.",&tolua_err);
        return 0;
    #endif
    }
    #endif


    #ifndef TOLUA_DISABLE_tolua_cw_GameObject_setSpeed00
    static int tolua_cw_GameObject_setSpeed00(lua_State* tolua_S)
    {
    #ifndef TOLUA_RELEASE
        tolua_Error tolua_err;
        if (!tolua_isusertype(tolua_S,1,"cwGameObject",0,&tolua_err) ||
            !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
            !tolua_isnoobj(tolua_S,3,&tolua_err))
            goto tolua_lerror;
        else
    #endif
        {
            cwGameObject* self = (cwGameObject*)  tolua_tousertype(tolua_S,1,0);
            float speed = ((float)  tolua_tonumber(tolua_S,2,0));
    #ifndef TOLUA_RELEASE
            if (!self) tolua_error(tolua_S,"invalid 'self' in function 'setSpeed'", NULL);
    #endif
            {
                self->setSpeed(speed);
            }
        }
        return 0;
    #ifndef TOLUA_RELEASE
        tolua_lerror:
        tolua_error(tolua_S,"#ferror in function 'setSpeed'.",&tolua_err);
        return 0;
    #endif
    }
    #endif


    #ifndef TOLUA_DISABLE_tolua_cw_GameObject_getMoveDir00
    static int tolua_cw_GameObject_getMoveDir00(lua_State* tolua_S)
    {
    #ifndef TOLUA_RELEASE
        tolua_Error tolua_err;
        if (!tolua_isusertype(tolua_S,1,"cwGameObject",0,&tolua_err) ||
            !tolua_isnoobj(tolua_S,2,&tolua_err))
            goto tolua_lerror;
        else
    #endif
        {
            cwGameObject* self = (cwGameObject*)  tolua_tousertype(tolua_S,1,0);
    #ifndef TOLUA_RELEASE
            if (!self) tolua_error(tolua_S,"invalid 'self' in function 'getMoveDir'", NULL);
    #endif
            cwVector2D& dir = self->moveDir();
            tolua_pushnumber(tolua_S,(lua_Number)dir.x);
            tolua_pushnumber(tolua_S,(lua_Number)dir.y);
        }
        return 2;
    #ifndef TOLUA_RELEASE
        tolua_lerror:
        tolua_error(tolua_S,"#ferror in function 'getMoveDir'.",&tolua_err);
        return 0;
    #endif
    }
    #endif


    #ifndef TOLUA_DISABLE_tolua_cw_GameObject_setMoveDir00
    static int tolua_cw_GameObject_setMoveDir00(lua_State* tolua_S)
    {
    #ifndef TOLUA_RELEASE
        tolua_Error tolua_err;
        if (!tolua_isusertype(tolua_S,1,"cwGameObject",0,&tolua_err) ||
            !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
            !tolua_isnumber(tolua_S,3,0,&tolua_err) ||
            !tolua_isnoobj(tolua_S,4,&tolua_err))
            goto tolua_lerror;
        else
    #endif
        {
            cwGameObject* self = (cwGameObject*)  tolua_tousertype(tolua_S,1,0);
            float dirX = ((float)  tolua_tonumber(tolua_S,2,0));
            float dirY = ((float)  tolua_tonumber(tolua_S,3,0));
    #ifndef TOLUA_RELEASE
            if (!self) tolua_error(tolua_S,"invalid 'self' in function 'setMoveDir'", NULL);
    #endif
            self->setMoveDir(dirX, dirY);
        }
        return 0;
    #ifndef TOLUA_RELEASE
        tolua_lerror:
        tolua_error(tolua_S,"#ferror in function 'getMoveDir'.",&tolua_err);
        return 0;
    #endif
    }
    #endif


    #endif


    TOLUA_API int tolua_cwLua_reg_types(lua_State* tolua_S)
    {
        //add by sunny
        tolua_usertype(tolua_S,"cwGameObject");
        tolua_usertype(tolua_S,"cwGravityObject");
        //end sunny


        return 1;
    }


    TOLUA_API int tolua_cwLua_reg(lua_State* tolua_S)
    {
    #ifdef __cplusplus
        tolua_cclass(tolua_S,"cwGameObject","cwGameObject","CCSprite",tolua_collect_cwGameObject);
    #else
        tolua_cclass(tolua_S,"cwGameObject","cwGameObject","CCSprite",NULL);
    #endif


        tolua_beginmodule(tolua_S,"cwGameObject");
        tolua_function(tolua_S,"create",tolua_cw_GameObject_create00);
        tolua_function(tolua_S,"speed",tolua_cw_GameObject_getSpeed00);
        tolua_function(tolua_S,"setSpeed",tolua_cw_GameObject_setSpeed00);
        tolua_function(tolua_S,"moveDir",tolua_cw_GameObject_getMoveDir00);
        tolua_function(tolua_S,"setMoveDir",tolua_cw_GameObject_setMoveDir00);
        tolua_endmodule(tolua_S);


    #ifdef __cplusplus
        tolua_cclass(tolua_S,"cwGravityObject","cwGravityObject","cwGameObject",tolua_collect_cwGravityObject);
    #else
        tolua_cclass(tolua_S,"cwGravityObject","cwGravityObject","cwGameObject",NULL);
    #endif


        tolua_beginmodule(tolua_S,"cwGravityObject");
        tolua_endmodule(tolua_S);


        return 1;
    }


    将tolua_cwLua_reg_types和tolua_cwLua_reg分别加到LuaCocos2d.cpp对应函数末尾,这样两个类cwGameObject与cwGravityObject就可以在lua中使用了。


    做到这还不能达到我的期望,原因是cocos2d的lua工程里,在AppDelegate::applicationDidFinishLaunching函数中只是加载并执行了hello.lua脚本文件,然后一切就都交给lua了,而我只是想使用lua实现一些AI方面的功能,即cwGameObject在需要执行AI时,调用lua中的一个函数。所以我需要的是一个可以调用lua函数的功能,查看了一下CCLuaEngine类,貌似没有我想要的,只能自己添了个函数:
    virtual int executeGlobalFunction(const char* functionName, float dt, CCObject* pObject, const char* typeName);
    functionName:被调lua函数名;dt:帧时间间隔;pObject:调用lua的对象;typeName:pObject对象类型
    实现如下:
    int CCLuaEngine::executeGlobalFunction(const char* functionName, float dt, CCObject* pObject, const char* typeName)
    {
        lua_getglobal(m_state, functionName);      


        if (!lua_isfunction(m_state, -1))
        {
            CCLOG("[LUA ERROR] name '%s' does not represent a Lua function", functionName);
            lua_pop(m_state, 1);
            return 0;
        }


        pushFloat(dt);
        pushCCObject(pObject, typeName);


        int error = lua_pcall(m_state, 2, 1, 0);            


        if (error)
        {
            CCLOG("[LUA ERROR] %s", lua_tostring(m_state, - 1));
            lua_pop(m_state, 1); // clean error message
            return 0;
        }


        // get return value
        if (!lua_isnumber(m_state, -1))
        {
            lua_pop(m_state, 1);
            return 0;
        }


        int ret = lua_tointeger(m_state, -1);
        lua_pop(m_state, 1);                                               
        return ret;
    }
    基本上是照着其他函数扒下来的,不同之处就是加了两个push。
    函数写的比较死,可以写一个接受可变参数的函数,做的通用些。


    假设我要在cwGameObject的upadte函数中调用“do_obj_update”lua函数,写法如下:
    void cwGameObject::update(float dt)
    {
        CCLuaEngine::defaultEngine()->executeGlobalFunction("do_obj_update", dt, this,"cwGameObject");
    }
    这样在创建cwGameObject时scheduleUpdate一下就可以了。


    lua脚本:
    -- for CCLuaEngine traceback
    function __G__TRACKBACK__(msg)
        print("----------------------------------------")
        print("LUA ERROR: " .. tostring(msg) .. " ")
        print(debug.traceback())
        print("----------------------------------------")
    end


    winSize = CCDirector:sharedDirector():getWinSize()


    -- avoid memory leak
    collectgarbage("setpause", 100)
    collectgarbage("setstepmul", 5000)


    function do_obj_update(dt, obj)
        local x, y = obj:getPosition()
        local vx, vy = obj:moveDir()


        x = x + vx*dt*obj:speed()
        y = y + vy*dt*obj:speed()


        if x < 0 then
            x = 0
            obj:setMoveDir(-vx, vy)
        end


        if x > winSize.width then
            x = winSize.width
            obj:setMoveDir(-vx, vy)
        end
       
        if y < 0 then
            y = 0
            obj:setMoveDir(vx, -vy)
        end


        if y > winSize.height then
            y = winSize.height
            obj:setMoveDir(vx, -vy)
        end


        obj:setPosition(x, y)
    end


    print("test.lua loaded.")


    脚本很简单,do_obj_update函数只是做了一些边框判断。
    别忘了修改AppDelegate::applicationDidFinishLaunching中加载的脚本文件名~~


    cocos2dx版本:cocos2d-2.0-x-2.0.3


    http://blog.csdn.net/honghaier/article/details/8700574

  • 相关阅读:
    关于导出Excel表中存在部门或用户数据权限问题
    进阶之路005 增删改查/数据导入导出之导出功能
    进阶之路004 增删改查/数据导入导出之查询功能
    进阶之路003 增删改查/数据导入导出之修改功能
    进阶之路002 增删改查/数据导入导出之删除功能
    进阶之路001 增删改查/数据导入导出之新增功能
    springboot常见注解 2020-01-19
    学习设计模式
    java并发
    java并发
  • 原文地址:https://www.cnblogs.com/byfei/p/6389786.html
Copyright © 2020-2023  润新知