Lua脚本和C++交互(三)

前两篇文章中介绍了C++调用lua、lua栈操作的一些相关知识。

下面说一下Lua的工具。我们下一步要用到其中的一个帮助我们的开发,其实,Lua里面有很多简化开发的工具,你可以去www.sourceforge.net去找一下。它们能够帮助你简化C++对象与Lua对象互转之间的代码。这里说几个有名的,当然可能不全。

(lua tinker)如果你的系统在windows下,而且不考虑移植,那么我强烈推荐你去下载一个叫做lua tinker的小工具,整个工具非常简单,一个.h和一个.cpp。直接就可以引用到你的工程中,连独立编译都不用,这是一个韩国人写的Lua与 C++接口转换的类,十分方便,代码简洁(居家旅行,必备良药)。它是基于模板的,所以你可以很轻松的把你的C++对象绑定到Lua中。代码较长,呵呵,有兴趣的朋友可以给我留言索要lua tinker的例子。就不贴在这里了。不过我个人不推荐这个东西,因为它在Linux下是编译不过去的。它使用了一种g++不支持的模板写法,虽然有人在尝试把它修改到Linux下编译,但据我所知,修改后效果较好的似乎还没有。不过如果你只是在  windows下,那就没什么可犹豫的,强烈推荐,你会喜欢它的。

(Luabinder)相信用过Boost库的朋友,或许对这个家伙很熟悉。它是一个很强大的Linux下Lua扩展包,帮你封装了很多Lua的复杂操作,主要解决了绑定C++对象和Lua对象互动的关系,非常强大,不过嘛,对于freeeyes而言,还是不推荐,因为freeeyes很懒,不想为了一个Lua还要去编译一个庞大的boost库,当然,见仁见智,如果你的程序本身就已经加载了boost,那么就应该毫不犹豫的选择它。

(lua++)呵呵,这是我最喜欢,也是我一直用到现在的库,比较前两个而言,lua++的封装性没有那么好,很多东西还是需要一点代码的,不过之所以我喜欢,是因为它是用C写的,可以在windows下和linux下轻松转换。如果鱼与熊掌不能兼得,那么我宁愿选择一个兼顾两者的东西,如果有的话,呵呵。当然,lua++就是这么一个东西,如果你继续看我的文章,或许你也会喜欢它的。

这里我们选择lua++作为我们继续进行下去的垫脚石吧。说到Lua++(http://www.codenix.com/~tolua/),这个东西还是挺有渊源的,请你先下载一个。我教你怎么编译。下面是我下载的lua++的目录结构:

还记得我昨天说过如何编译Lua么,现在请你再做一遍,不同的是,请把lua++的程序包中的src/lib中的所有h和cpp,还有include下的那个.h拷贝到你上次建立的lua工程中。最后记得把tolua++.h放在你的Include文件夹下。下图为整个项目的目录结构(最终运行成功的目录结构):

行了,我们把上次CLuaFn类稍微改一下。

extern "C"
{
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
    #include "tolua++.h"   //这里加一行
};
#include "_ParamData.h"
#include "CTest.h"
class CLuaFn
{
public:
    CLuaFn(void);
    ~CLuaFn(void);

    void Init();    //初始化Lua对象指针参数
    void Close();    //关闭Lua对象指针

    bool LoadLuaFile(const char* pFileName);    //加载指定的Lua文件
    bool CLuaFn::CallFileFn(const char* pFunctionName, CParamGroup& ParamIn, CParamGroup& ParamOut);        //执行指定Lua文件中的函数
    //参数入栈
    bool CLuaFn::PushLuaData(lua_State* pState, _ParamData* pParam);
    //参数出栈
    bool CLuaFn:: PopLuaData(lua_State* pState, _ParamData* pParam, int nIndex);  

    //新对象的创建、销毁
    static int tolua_new_CTest(lua_State* pState);
    static int tolua_delete_CTest(lua_State* pState) ;
    static int tolua_SetData_CTest(lua_State* pState);
    static int tolua_GetData_CTest(lua_State* pState);

    bool InitClass(); 

private:
    lua_State* m_pState;    //这个是Lua的State对象指针,你可以一个Lua文件对应一个

};

行了,这样我们就能用Lua++下的功能了。
昨天,大家看到了 bool CallFileFn(const char* pFunctionName, int nParam1, int nParam2);这个函数的运用。演示了真么调用Lua函数。
下面,我改一下,这个函数。为什么?还是因为freeeyes很懒,我可不想每有一个函数,我都要写一个C++函数去调用,太累!我要写一个通用的!支持任意函数调用的接口!
于是我创建了两个类。支持任意参数的输入和输出,并打包送给lua去执行

//支持任意参数的输入和输出,并打包送给lua去执行
#ifndef _PARAMDATA_H
#define _PARAMDATA_H  

#include <vector>  

#define MAX_PARAM_200 200
using namespace std;  

struct _ParamData
{
public:
    void* m_pParam;
    char  m_szType[MAX_PARAM_200];
    int   m_TypeLen;
public:
    _ParamData()
    {
        m_pParam    = NULL;
        m_szType[0] = ‘\0‘;
        m_TypeLen   = 0;
    };  

    _ParamData(void* pParam, const char* szType, int nTypeLen)
    {
        SetParam(pParam, szType, nTypeLen);
    }
    ~_ParamData() {};  

    void SetParam(void* pParam, const char* szType, int nTypeLen)
    {
        m_pParam = pParam;
        sprintf(m_szType, "%s", szType);
        m_TypeLen = nTypeLen;
    };  

    bool SetData(void* pParam, int nLen)
    {
        if(m_TypeLen < nLen)
        {
            return false;
        }  

        if(nLen > 0)
        {
            memcpy(m_pParam, pParam, nLen);
        }
        else
        {
            memcpy(m_pParam, pParam, m_TypeLen);
        }
        return true;
    }  

    void* GetParam()
    {
        return m_pParam;
    }  

    const char* GetType()
    {
        return m_szType;
    }  

    bool CompareType(const char* pType)
    {
        if(0 == strcmp(m_szType, pType))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
};  

class CParamGroup
{
public:
    CParamGroup() {};
    ~CParamGroup()
    {
        Close();
    };  

    void Init()
    {
        m_vecParamData.clear();
    };  

    void Close()
    {
        for(int i = 0; i < (int)m_vecParamData.size(); i++)
        {
            _ParamData* pParamData = m_vecParamData[i];
            delete pParamData;
            pParamData = NULL;
        }
        m_vecParamData.clear();
    };  

    void Push(_ParamData* pParam)
    {
        if(pParam != NULL)
        {
            m_vecParamData.push_back(pParam);
        }
    };  

    _ParamData* GetParam(int nIndex)
    {
        if(nIndex < (int)m_vecParamData.size())
        {
            return m_vecParamData[nIndex];
        }
        else
        {
            return NULL;
        }
    };  

    int GetCount()
    {
        return (int)m_vecParamData.size();
    }  

private:
    typedef vector<_ParamData*> vecParamData;
    vecParamData m_vecParamData;
};  

#endif 

我创建了两个类,把Lua要用到的类型,数据都封装起来了。这样,我只需要这么改写这个函数。
bool CallFileFn(const char* pFunctionName, CParamGroup& ParamIn, CParamGroup& ParamOut);
它就能按照不同的参数自动给我调用,嘿嘿,懒到家吧!
其实这两个类很简单,_ParamData是参数类,把你要用到的参数放入到这个对象中去,标明类型的大小,类型名称,内存块。而CParamGroup负责将很多很多的_ParamData打包在一起,放在vector里面。
好了,让我们看看CallFileFn函数里面我怎么改的。

#include "CLuaFn.h"

CLuaFn::CLuaFn(void){m_pState = NULL;};        //这句干嘛
CLuaFn::~CLuaFn(void){};

//初始化函数
void CLuaFn::Init()
{
    if (NULL == m_pState)
    {
        m_pState = lua_open();    //返回一个lua对象指针
        luaL_openlibs(m_pState);    //加载了所有你可能用到的Lua基本库
    }
}

//关闭Lua对象并释放资源
void CLuaFn::Close()
{
    if(NULL != m_pState)
    {
        lua_close(m_pState);
        m_pState = NULL;
    }
}

bool CLuaFn::LoadLuaFile(const char* pFileName)
{
    int nRet = 0;
    if (NULL == m_pState)
    {
        printf("[CLuaFn::LoadLuaFile]m_pState is NULL.\n");
        return false;
    }
    //加载文件的时候尽量放在程序的初始化中
    nRet = luaL_dofile(m_pState, pFileName);
    if (nRet != 0)
    {
        printf("[CLuaFn::LoadLuaFile]luaL_loadfile(%s) is file(%d)(%s).\n", pFileName, nRet, lua_tostring(m_pState, -1));
        return false;
    }
    return true;
}

//参数入栈
bool CLuaFn::PushLuaData(lua_State* pState, _ParamData* pParam)
{
    if(pParam == NULL)
    {
        return false;
    }  

    if(pParam->CompareType("string"))
    {
        lua_pushstring(m_pState, (char* )pParam->GetParam());
        return true;
    }  

    if(pParam->CompareType("int"))
    {
        int* nData = (int* )pParam->GetParam();
        lua_pushnumber(m_pState, *nData);
        return true;
    }
    else
    {
        void* pVoid = pParam->GetParam();
        //

        tolua_pushusertype(m_pState, pVoid, pParam->GetType());
        return true;
    }
}  

// 参数出栈
bool CLuaFn:: PopLuaData(lua_State* pState, _ParamData* pParam, int nIndex)
{
    if(pParam == NULL)
    {
        return false;
    }  

    if(pParam->CompareType("string"))
    {
        if (lua_isstring(m_pState, nIndex) == 1)
        {
            const char* pData = (const char*)lua_tostring(m_pState, nIndex);
            pParam->SetData((void* )pData, (int)strlen(pData));
        }
        return true;
    }  

    if(pParam->CompareType("int"))
    {
        if (lua_isnumber(m_pState, nIndex) == 1)
        {
            int nData = (int)lua_tonumber(m_pState, nIndex);
            pParam->SetData(&nData, sizeof(int));
        }
        return true;
    }
    else
    {
        pParam->SetData(tolua_tousertype(m_pState, nIndex, NULL), -1);
        return true;
    }
}  

//调用函数
bool CLuaFn::CallFileFn(const char* pFunctionName, CParamGroup& ParamIn, CParamGroup& ParamOut)
{
    int nRet = 0;
    int i    = 0;
    if(NULL == m_pState)
    {
        printf("[CLuaFn::CallFileFn]m_pState is NULL.\n");
        return false;
    }  

    lua_getglobal(m_pState, pFunctionName);  

    //加载输入参数
    for(i = 0; i < ParamIn.GetCount(); i++)
    {
        PushLuaData(m_pState, ParamIn.GetParam(i));
    }  

    nRet = lua_pcall(m_pState, ParamIn.GetCount(), ParamOut.GetCount(), 0);
    if (nRet != 0)
    {
        printf("[CLuaFn::CallFileFn]call function(%s) error(%s).\n", pFunctionName, lua_tostring(m_pState, -1));
        return false;
    }  

    //获得输出参数
    int nPos = 0;
    for(i = ParamOut.GetCount() - 1; i >= 0; i--)
    {
        nPos--;
        PopLuaData(m_pState, ParamOut.GetParam(i), nPos);
    }  

    int nCount = lua_gettop(m_pState);
    //根据返回参数的个数重新设置栈顶, 这样做可以返回任意数量的栈而且清除干净
    lua_settop(m_pState, -1-ParamOut.GetCount());  

    return true;
}  

/* ************************************************************* */

int CLuaFn::tolua_new_CTest(lua_State* pState)
{
    CTest* pTest = new CTest();
    //将一个已经在Lua注册的"CTest"对象指针,压入数据栈
    tolua_pushusertype(pState, pTest, "CTest");
    return 1;
}  

int CLuaFn::tolua_delete_CTest(lua_State* pState)
{
    //将数据栈下的对象以(CTest* )的指针形式弹出来
    CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0);
    if(NULL != pTest)
    {
        delete pTest;
    }
    return 1;
}  

 /*tolua_SetData_CTest()函数和tolua_GetData_CTest分别对应CTest的SetData方法和GetData()方法。
 因为我们的SetData方法里面存在变量,那么同样,我们需要使用const char* pData = tolua_tostring(pState, 2, 0);将参数弹出来,
 然后输入到pTest->SetData(pData);对象中去,当然,你可以有更多若干个参数*/
int CLuaFn::tolua_SetData_CTest(lua_State* pState)
{
    CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0);
    const char* pData = tolua_tostring(pState, 2, 0);  

    if(pData != NULL && pTest != NULL)
    {
        pTest->SetData(pData);
    }
    return 1;
}  

int CLuaFn::tolua_GetData_CTest(lua_State* pState)
{
    CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0);
    if(pTest != NULL)
    {
        char* pData = pTest->GetData();
        tolua_pushstring(pState, pData);
    }
    return 1;
}  

/* ************************************************************* */

bool CLuaFn::InitClass()
{
    if(NULL == m_pState)
    {
        printf("[CLuaFn::InitClass]m_pState is NULL.\n");
        return false;
    } 

    tolua_open(m_pState);
    tolua_module(m_pState, NULL, 0);
    tolua_beginmodule(m_pState, NULL);
    tolua_usertype(m_pState, "CTest");
    tolua_cclass(m_pState, "CTest", "CTest", "", tolua_delete_CTest);
    //只注册一个模块,比如,我们管CTest叫做"CTest",保持和C++的名称一样。这样在Lua的对象库中就会多了一个CTest的对象描述,等同于string,number等等基本类型
    tolua_beginmodule(m_pState, "CTest");
    tolua_function(m_pState, "new", tolua_new_CTest);
    //将Lua里面CTest对象的"SetData"绑定到你的tolua_SetData_CTest()函数中去
    tolua_function(m_pState, "SetData", tolua_SetData_CTest);
    tolua_function(m_pState, "GetData", tolua_GetData_CTest);
    //tolua_beginmodule()和tolua_endmodule()对象必须成对出现,如果出现不成对的,你注册的C++类型将会失败
    tolua_endmodule(m_pState);
    tolua_endmodule(m_pState);  

    return true;
} 

下面来看一个类(头文件)。假设我们要把这个对象,传输给Lua进行调用。

#ifndef _TEST_H
#define _TEST_H
#include<stdio.h>
class CTest
{
public:
    CTest(void);
    ~CTest(void);  

    char* GetData();
    void SetData(const char* pData);  

private:
    char m_szData[200];
};  

#endif 

这个类里面有两个函数,一个是GetData(),一个是SetData(),之所以这么写,我要让Lua不仅能使用我的类,还可以给这个类使用参数。
那么,cpp文件,我们姑且这样写。(当然,你可以进行修改,按照你喜欢的方式写一个方法,呵呵)

 /*这是一个标准的类,我需要这个类在Lua里面可以创造出来,并赋予数值,
 甚至我可以把CTest作为一个Lua函数参数,传给Lua函数让它去给我处理*/
#include "CTest.h"

CTest::CTest(void){};
CTest::~CTest(void){};  

char* CTest::GetData()
{
    printf("[CTest::GetData]%s.\n", m_szData);
    return m_szData;
}

void CTest::SetData(const char* pData)
{
    sprintf(m_szData, "%s", pData);
}

这是一个标准的类,我需要这个类在Lua里面可以创造出来,并赋予数值,甚至我可以把CTest作为一个Lua函数参数,传给Lua函数让它去给我处理。让我们来看看怎么做。如果使用标准的Lua语法,有点多,所以我就借用一下上次提到的tolua来做到这一切,我一句句的解释。姑且我们把这些代码放在LuaFn.cpp里面。

/* ************************************************************* */

int CLuaFn::tolua_new_CTest(lua_State* pState)
{
    CTest* pTest = new CTest();
    //将一个已经在Lua注册的"CTest"对象指针,压入数据栈
    tolua_pushusertype(pState, pTest, "CTest");
    return 1;
}  

int CLuaFn::tolua_delete_CTest(lua_State* pState)
{
    //将数据栈下的对象以(CTest* )的指针形式弹出来
    CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0);
    if(NULL != pTest)
    {
        delete pTest;
    }
    return 1;
}  

 /*tolua_SetData_CTest()函数和tolua_GetData_CTest分别对应CTest的SetData方法和GetData()方法。
 因为我们的SetData方法里面存在变量,那么同样,我们需要使用const char* pData = tolua_tostring(pState, 2, 0);将参数弹出来,
 然后输入到pTest->SetData(pData);对象中去,当然,你可以有更多若干个参数*/
int CLuaFn::tolua_SetData_CTest(lua_State* pState)
{
    CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0);
    const char* pData = tolua_tostring(pState, 2, 0);  

    if(pData != NULL && pTest != NULL)
    {
        pTest->SetData(pData);
    }
    return 1;
}  

int CLuaFn::tolua_GetData_CTest(lua_State* pState)
{
    CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0);
    if(pTest != NULL)
    {
        char* pData = pTest->GetData();
        tolua_pushstring(pState, pData);
    }
    return 1;
}  

/* ************************************************************* */

看看这几个静态函数在干什么。
我要在Lua里面使用CTest,必须让Lua里这个CTest对象能够顺利的创造和销毁。tolua_new_CTest()和tolua_delete_CTest()就是干这个的。
tolua_pushusertype(pState, pTest, "CTest"); 这句话的意思是,将一个已经在Lua注册的"CTest"对象指针,压入数据栈。
同理,CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0);是将数据栈下的对象以(CTest* )的指针形式弹出来。
tolua_SetData_CTest()函数和tolua_GetData_CTest分别对应CTest的SetData方法和GetData()方法。因为我们的SetData方法里面存在变量,那么同样,我们需要使用const char* pData = tolua_tostring(pState, 2, 0);将参数弹出来,然后输入到pTest->SetData(pData);对象中去,当然,你可以有更多若干个参数。随你的喜好。这里只做一个举例。
好了,你一定会问,这么多的静态函数,用在哪里?呵呵,当然是给Lua注册,当你把这些数据注册到Lua里面,你就可以轻松的在Lua中使用它们。
让我们看看,注册是怎么做到的。
还是在CLuaFn类里面,我们增加一个函数。比如叫做bool InitClass();

bool CLuaFn::InitClass()
{
    if(NULL == m_pState)
    {
        printf("[CLuaFn::InitClass]m_pState is NULL.\n");
        return false;
    } 

    tolua_open(m_pState);
    tolua_module(m_pState, NULL, 0);
    tolua_beginmodule(m_pState, NULL);
    tolua_usertype(m_pState, "CTest");
    tolua_cclass(m_pState, "CTest", "CTest", "", tolua_delete_CTest);
    //只注册一个模块,比如,我们管CTest叫做"CTest",保持和C++的名称一样。这样在Lua的对象库中就会多了一个CTest的对象描述,等同于string,number等等基本类型
    tolua_beginmodule(m_pState, "CTest");
    tolua_function(m_pState, "new", tolua_new_CTest);
    //将Lua里面CTest对象的"SetData"绑定到你的tolua_SetData_CTest()函数中去
    tolua_function(m_pState, "SetData", tolua_SetData_CTest);
    tolua_function(m_pState, "GetData", tolua_GetData_CTest);
    //tolua_beginmodule()和tolua_endmodule()对象必须成对出现,如果出现不成对的,你注册的C++类型将会失败
    tolua_endmodule(m_pState);
    tolua_endmodule(m_pState);  

    return true;
} 

上面的代码,就是我把上面的几个静态函数,绑定到Lua的基础对象中去。
tolua_beginmodule(m_pState, "CTest");是只注册一个模块,比如,我们管CTest叫做"CTest",保持和C++的名称一样。这样在Lua的对象库中就会多了一个CTest的对象描述,等同于string,number等等基本类型,同理,你也可以用同样的方法,注册你的MFC类。是不是有点明白了?这里要注意,tolua_beginmodule()和tolua_endmodule()对象必须成对出现,如果出现不成对的,你注册的C++类型将会失败。
tolua_function(m_pState, "SetData", tolua_SetData_CTest);指的是将Lua里面CTest对象的"SetData"绑定到你的tolua_SetData_CTest()函数中去。

好的,让我们来点激动人心的东西。还记得我们的Simple.lua的文件么。我们来改一下它。

function func_Add(x, y)
-- New了一个CTest对象,并进行赋值操作,最后把结果打印在屏幕上
local test = CTest:new()
test:SetData("I‘m xiaotian")
test:GetData()

return x..y;
end

我在这个函数里面,New了一个CTest对象,并进行赋值操作,最后把结果打印在屏幕上。你或许会问,最后一句不是x+y么,怎么变成了x..y,呵呵,在Lua中,..表示联合的意思,就好比在C++里面, string strName += "freeeyes"。原来觉得x+y有点土,索性返回一个两个字符串的联合吧。
好了,我们已经把我们的这个CTest类注册到了Lua里面,让我们来调用一下吧。修改一下Main函数。变成以下的样子。

#include "CLuaFn.h"
int main(int argc, char* argv[])
{
    CLuaFn CLuaFn;
    CLuaFn.Init();
    CLuaFn.InitClass();
    CLuaFn.LoadLuaFile("Sample.lua");
    CParamGroup ParamIn;
    CParamGroup ParamOut;
    char szData1[20] = {‘\0‘};

    sprintf(szData1, "[yang]");
    _ParamData* pParam1 = new _ParamData(szData1, "string", (int)strlen(szData1));
    ParamIn.Push(pParam1);  

    char szData2[20] = {‘\0‘};
    sprintf(szData2, "[xiaotian]");
    _ParamData* pParam2 = new _ParamData(szData2, "string", (int)strlen(szData2));
    ParamIn.Push(pParam2);  

    char szData3[40] = {‘\0‘};
    _ParamData* pParam3 = new _ParamData(szData3, "string", 40);
    ParamOut.Push(pParam3);

    CLuaFn.CallFileFn("func_Add", ParamIn, ParamOut);
    char* pData = (char* )ParamOut.GetParam(0)->GetParam();
    printf("[Main]Sum = %s.\n", pData);
    getchar();
    return 0;
}

运行一下:

时间: 2024-10-15 05:17:44

Lua脚本和C++交互(三)的相关文章

Lua脚本和C++交互(一)

现在,越来越多的C++服务器和客户端融入了脚本的支持,尤其在网游领域,脚本语言已经渗透到了方方面面,比如你可以在你的客户端增加一个脚本,这个脚本将会帮你在界面上显示新的数据,亦或帮你完成某些任务,亦或帮你查看别的玩家或者NPC的状态...如此等等. 但是我觉得,其实脚本语言与C++的结合,远远比你在游戏中看到的特效要来的迅猛.它可以运用到方方面面的领域,比如你最常见的应用领域.比如,你可以用文本编辑器,写一个脚本语言,然后用你的程序加载一下,就会产生出很绚丽的界面.亦或一两句文本语言,就会让你的

Lua脚本和C++交互(四)

上一篇中,你已经可以在Lua里面用C++的函数了,那么咱们再增加一点难度,比如,我有一个CTest对象,要作为一个参数,传输给func_Add()执行,怎么办?很简单,如果你对上面的代码仔细阅读,你会发现下面的代码一样简洁.为了支持刚才要说的需求,我们需要把Sample.lua再做一点修改. function func_Add(x, y, f) -- New了一个CTest对象,并进行赋值操作,最后把结果打印在屏幕上 -- local test = CTest:new() -- test:Set

Lua脚本和C++交互(二)

上一节讲了一些基本的Lua应用,下面,我要强调一下,Lua的栈的一些概念,因为这个确实很重要,你会经常用到.熟练使用Lua,最重要的就是要时刻知道什么时候栈里面的数据是什么顺序,都是什么.如果你能熟练知道这些,实际你已经是Lua运用的高手了.当你初始化一个栈的时候,它的栈底是1,而栈顶相对位置是-1,说形象一些,你可以把栈想象成一个环,有一个指针标记当前位置,如果-1,就是当前栈顶,如果是-2就是当前栈顶前面一个参数的位置.以此类推.当然,你也可以正序去取,这里要注意,对于Lua的很多API,下

Win32下 Qt与Lua交互使用(三):在Lua脚本中connect Qt 对象

话接上文.笔者为了方便使用Lua,自己编写了一个Lua的类.主要代码如下: QLua.h 1 #ifndef QLUA_H 2 #define QLUA_H 3 4 // own 5 #include "include/lua.hpp" 6 7 // qt 8 #include <QObject> 9 #include <QFile> 10 #include <QDebug> 11 12 #include <QWidget> 13 #in

Win32下 Qt与Lua交互使用(二):在Lua脚本中使用Qt类

话接上篇.成功配置好Qt+Lua+toLua后,我们可以实现在Lua脚本中使用各个Qt的类.直接看代码吧. #include "include/lua.hpp" #include <QWidget> #include <QApplication> #include <QFile> #include <QDebug> static int tolua_new_QWidget(lua_State* pState) { QWidget* wid

Win32下 Qt与Lua交互使用(四):在Lua脚本中自由执行Qt类中的函数

话接上篇.通过前几篇博客,我们实现在Lua脚本中执行Qt类中函数的方法,以及在Lua脚本中连接Qt对象的信号与槽. 但是,我们也能发现,如果希望在Lua脚本中执行Qt类的函数,就必须绑定一个真正实现功能的函数.如QWidget::show(),需要写一个在栈中取出widget指针,widget调用show()函数的方式.如果希望在Lua中调用大量函数,就需要编写大量的C++实现函数.有没有什么省时省力的好方法呢? 上一篇中我们实现了在Lua脚本中连接信号与槽.我们只是传过去了两个QObject的

Lua脚本在C++下的舞步(入门指引)(转)

http://www.cnblogs.com/hmxp8/archive/2011/11/23/2259777.html 转帖来自:http://www.acejoy.com/bbs/viewthread.php?tid=1931&extra=page%3D1 现在,越来越多的C++服务器和客户端融入了脚本的支持,尤其在网游领域,脚本语言已经渗透到了方方面面,比如你可以在你的客户端增加一个脚本,这个脚本将会帮你在界面上显示新的数据,亦或帮你完成某些任务,亦或帮你查看别的玩家或者NPC的状态...

Lua脚本编程:Lua语言入门

Lua是一门简单而强大的语言,其本身强大的扩展性使得这门语言在游戏设计等领域发挥着重要的作用.博主曾在Unity3D中使用过这门语言,并且针对Lua和Unity.C++等方面的内容进行了学习和讨论.最近因为在[游戏脚本高级编程]这本书中详细介绍了Lua脚本的相关内容,因此在这里记录下博主的读书心得,方便以后在需要的时候查阅. Lua系统构成 Lua系统由Lua链接库.Luac编译器.Lua解释器三部分构成. * Lua链接库主要由lua.lib和lua.h这两个文件组成.Lua链接库主要负责对自

【COCOS2DX-LUA 脚本开发之一】在Cocos2dX游戏中使用Lua脚本进行游戏开发(基础篇)并介绍脚本在游戏中详细用途!

[COCOS2DX-LUA 脚本开发之一]在Cocos2dX游戏中使用Lua脚本进行游戏开发(基础篇)并介绍脚本在游戏中详细用途! 分类: [Cocos2dx Lua 脚本开发 ] 2012-04-16 10:08 30803人阅读 评论(18) 收藏 举报 游戏脚本luaanimationpython 本站文章均为李华明Himi原创,转载务必在明显处注明:转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-cocos2dx/681.htm