已阅读5页,还剩17页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
tolua+初探(一)(转)2010-01-29 10:22用luaplus试验了下,想把简单的C+类映射到lua脚本中不难,但是复杂一点的,比方说类的聚合、继承等,比较麻烦。我试验了两天,用表中表来实 现是可以的,但自己弄太麻烦了。说到底,我只是想用一下而已,不是想从头弄一个系统。 用CEGUI时发现它用了tolua+,从网上DOWN了源码(1.0.92),支持Lua5.1。我用VS2005,用源码包里的sln顺利编译出 tolua+.exe。lib据说要用第三方的scons来弄,嫌麻烦,我直接建了个VC动态库工程,将srclib下的文件加进来,修改了 tolua+.h,重定义一下TOLUA_API,编译通过。 #ifndef TOLUA_API #ifdef _WINDLL #define TOLUA_API _declspec(dllexport) #else #define TOLUA_API extern #endif #endif 这只是个简单的定义,如果在其它的DLL中用tolua+.h会出问题(我直接用了_WINDLL宏来判断),自己定义一个其它的宏就可以了。 我要用动态链接库,不想用静态库。下了lua5.1.3的源码包,编译动态库。 编译时都选择MD,不选MT,后者在项目中有多个模块时容易出问题,尤其是有的模块用MD,有的模块用MT时更容易出问题。我那天就因为这个出了400多个错误,几乎抓狂。 这样我现在有了tolua+.exe,lua5.1.dll,tolua+.dll,以及对应的lib文件。可以进行试验了。tolua+初探(二)(转)2010-01-29 10:23tolua+的源码包中有很多测试例子。这里我用更最简单的例子来学习。 第一个例子是数组。仅仅是把C+中的一个数组导出到Lua中,可以在脚本中访问并修改。 tarray.pkg文件: $#include tarray.h extern int g_Arr10Arr; 很简单,$#include tarray.h,包含实际的C头文件,这个语句会去掉$符号,直接插入到tolua+.exe生成的C文件中。文档中说$lfile,$cfile,$ifile会特别处理,我试验了下,不像说的那个样子。 extern int g_Arr10Arr,tolua+会分析这一句,将g_Arr10映射到lua中的Arr上。其中后面是你想在lua中看到的变量名。 tarray.h文件也只有一句: #ifndef _TESTARRAY_H #define _TESTARRAY_H extern int g_Arr10; #endif g_Arr的实例在一个cpp文件中。 用tolua+.exe生成用于导出c+对象到lua脚本中的CPP文件: tolua+.exe -n tarray -o tarray.cpp tarray.pkg -n tarray选项指定包的名字为tarray。如果不用-n显式指定,tolua+.exe会生成一个和pkg文件名一样的包名,同时生成tolua_*_open(lua_State*)入口函数。 将此CPP文件加入工程。 在工程中加入lua5.1.lib,tolua+.lib,包含lua.hpp,tolua+.h,然后写点测试代码,就可以编译了。程序主文件array.cpp: #include stdafx.h #include lua.hpp int tolua_tarray_open (lua_State* tolua_S); #include tarray.h int g_Arr10=.0; int _tmain(int argc, _TCHAR* argv) . lua_State * L = lua_open(); int i=0; for(i=0; i10; i+) g_Arri = i; luaopen_base(L); tolua_tarray_open(L); luaL_dofile(L, .scriptsarray.lua); printf(now in c+, re-show Arr: ); for(i=0; i10; i+) printf(%d , g_Arri); printf( ); lua_close(L); return 0; luaopen_tarray_open是必须要调用的,tolua+.exe根据你命令行中指定的名字生成tolua_*_open函数。该函数用 来导出c+对象到lua脚本中,所以必须在你执行lua脚本之前调用。函数的原型在由tolua+.exe生成的cpp文件中。 脚本文件array.lua内容如下: print(now in lua script! try to print Arr by name:) print(Arr) -print contents of Arr print(now print Arr:) for i=0,9 do print(Arri) end -change contents of Arr print(now change the Arr.) for i=0,9 do Arri = i*2 end 第一个例子到此为止。编译后可以进行测试了。 我针对DEBUG和release版本生成了不同的DLL和LIB文件,好用于测试。总结一下步骤: 1.编写C头文件,定义想导出的对象 2.编写pkg文件,包含之前的C头文件,用tolua+可识别的规则定义你要导出的对象 3.用tolua+.exe生成CPP文件 4.将3生成的文件,1中的头文件,tolua+的头文件,lua的头文件及相关的库加入工程。 5.编写lua脚本文件。tolua+初探(三)(转)2010-01-29 10:23 利用tolua+导出类到lua中简单方便,你可以导出静态成员函数、普通成员函数、静态成员变量、普通成员变量,你也可以指定类的哪些方法被导出。你可以将具有单继承的派生类导出,派生类可以很自然地访问基类的方法。更多的细节,请参考tolua+的在线文档。 首先生成实际的c+头文件,定义我们要导出的类。tclass.h内容如下: #ifndef _TESTCLASS_H #define _TESTCLASS_H #include class CNumber. /tolua_exportpublic: /tolua_begin CNumber():m_nNum(0). CNumber(int num):m_nNum(num). CNumber() . void SetNumber(int num) m_nNum = num; int GetNumber() . return m_nNum; int Add(int num) . m_nNum += num; return m_nNum; /tolua_end protected: int m_nNum; ;/tolua_export /tolua_begin class CMessage . /tolua_end public: /tolua_begin CMessage() . strcpy(m_szMessage, initial message); CMessage(char *initmsg) . if(initmsg) strncpy(m_szMessage, initmsg, 256); CMessage() . void SetMessage(char *msg) . if(msg) . strncpy(m_szMessage, msg, 256); char *GetMessage() . return m_szMessage; void ShowMessage() . printf(this message is printed in c+ code when lua call ShowMessage:%s , m_szMessage); /tolua_end protected: char m_szMessage256; ;/tolua_export #endif 为了方便,我把实现也放在了头文件中。 接下来定义pkg文件,tclass.pkg。 $#include tclass.h class CNumber. /tolua_export public: /tolua_begin CNumber();CNumber(int num); CNumber(void);void SetNumber(int num);int GetNumber(void);int Add(int num); /tolua_end ;/tolua_export /tolua_begin class CMessage . /tolua_end public: /tolua_begin CMessage(void);CMessage(char * initmsg);CMessage(void);void SetMessage(char *msg); char *GetMessage(); void ShowMessage();/tolua_end ;/tolua_export 和我们的第一个数组的例子一样,包含实际的C头文件,用tolua+的语法声明你想导出的部分。在导出类的时候,构造函数被映射到lua中的new,析 构函数被映射为delete。他们的用法可以在后面的lua代码中看到。接下来就是用tolua+.exe生成用于完成“导出类到lua”功能的CPP 文件了。 tolua+.exe -n tclass -o tclass.cpp tclass.pkg 把tclass.h和tclass.cpp加入到工程中。编写驱动代码,调用lua脚本文件。这部分如下: #include lua.hpp #include tclass.h int tolua_tclass_open(lua_State *); int _tmain(int argc, _TCHAR* argv) . lua_State *L = luaL_newstate(); luaopen_base(L); tolua_tclass_open(L); luaL_dofile(L, .scriptsclasstest.lua); lua_close(L); return 0; 编写lua脚本文件classtest.lua,内容如下: print(now in classtest.lua!) -new a CNumber Object print(now allocate a CNumber Object:) num=CNumber:new() num2=CNumber:new(222) print(init, num: .num:GetNumber() print(init, num2: .num2:GetNumber() print(now call SetNumber(6) num:SetNumber(6) print(now the num:.num:GetNumber(); num:delete() print(num is deleted, access GetNumber is invalid!) print(invalid call, result: .num:GetNumber() -new a CMessage Object msg=CMessage:new() print(init msg: .msg:GetMessage() print(now change the msg by call msg:SetMessage(changed message) msg:SetMessage(changed message) print(now msg: .msg:GetMessage() msg:ShowMessage() msg:delete() print(msg is deleted, access GetMessage is invalid!) print(inivalid call, result: .msg:GetMessage() OK,简单的几步工作,我们已经可以在lua中使用C+类了。有两点要注意: 1.pkg文件要包含实际的C头文件。 2.pkg文件中要声明需要导出到lua中的类,类名与实际的C头文件中的一样,只声明你想导出的部分即可。tolua+初探(四)(转)2010-01-29 10:24 聚合是最常见的构造新类的方式了,另一个是继承。tolua+支持单继承,后面会提到继承的例子。这里先看看怎么将利用了聚合的类导出到lua中。 我的目的是想在Lua中使用C+类的实例,而不是在lua中生成C+类实例,所以我在利用tolua+向lua导出类时一般不导出构造函数,这样就 无法在lua中生成类实例。 但是为了演示的方便,这个例子中用到的两个简单类CNumber和CMessage仍然导出了构造函数。 另外一个单件(singleton)CTestSystem的构造函数、拷贝构造函数、=操作符都被声明为protected,在向lua导出时只导出了 几个方法。你无法在lua中生成它的实例,即便在C+中也不行,只能通过其静态成员函数GetSingleton()获取。 实际的头文件classg.h如下: #ifndef _CLASSGROUP_H #define _CLASSGROUP_H #include class CNumber. /tolua_export public: /tolua_begin CNumber():m_nNum(0) . CNumber(int num):m_nNum(num) . CNumber() . void SetNumber(int num) . m_nNum = num; int GetNumber() . return m_nNum; int Add(int num) . m_nNum += num; return m_nNum; /tolua_end protected: int m_nNum; ;/tolua_export /tolua_begin class CMessage . /tolua_end public: /tolua_begin CMessage() . strcpy(m_szMessage, initial message); CMessage(char *initmsg) . if(initmsg) strncpy(m_szMessage, initmsg, 256); CMessage() . void SetMessage(char *msg) . if(msg) . strncpy(m_szMessage, msg, 256); char *GetMessage() . return m_szMessage; oid ShowMessage() . printf(this message is printed in c+ code when lua call ShowMessage:%s , m_szMessage); /tolua_end protected: char m_szMessage256; ;/tolua_export class CTestSystem. public: static CTestSystem & GetSingleton().static CTestSystem sys; return sys;CNumber & GetNumberObj().return m_Number; CMessage & GetMessageObj().return m_Message; protected: CTestSystem(). CTestSystem(const CTestSystem&); CTestSystem & operator=(const CTestSystem& rhs); CTestSystem(). private: CNumber m_Number; CMessage m_Message; ; #endif 接下来是pkg文件: $#include classg.h class CNumber. /tolua_export public: /tolua_begin CNumber(); CNumber(int num); CNumber(void); void SetNumber(int num); int GetNumber(void); int Add(int num); /tolua_end ;/tolua_export /tolua_begin class CMessage . /tolua_end public: /tolua_begin CMessage(void); CMessage(char * initmsg); CMessage(void); void SetMessage(char *msg); char *GetMessage(); void ShowMessage(); /tolua_end ;/tolua_export class CTestSystem . static CTestSystem & GetSingleton(); CNumber & GetNumberObj(); CMessage & GetMessageObj(); ; 我只导出需要的部分。有点遗憾的是,tolua+的手册中说无法通过修改你要导出的类的名字,这样的话,如果我想在lua中使用另外的名字,就要用别的办法了(文档中说$renaming可以,未试验,存疑)。 驱动部分和之前的例子中类似: #include classg.h #include lua.hpp int tolua_classgroup_open(lua_State*); int _tmain(int argc, _TCHAR* argv). lua_State * L = luaL_newstate(); luaopen_base(L); tolua_classgroup_open(L); luaL_dofile(L, .scriptsclassgroup.lua); lua_close(L); return 0; 一直没有介绍上面用到的几个函数。在lua5.1中,用来生成lua状态对象的lua_open函数不再直接可用,替换为lua_newstate,不过 lua_newstate要提供内存分配函数,lua扩展库提供了无参数的luaL_newstate,用起来方面。同时为了向前兼容,还做了宏定 义#define lua_open luaL_newstate()。所以你仍然可以用lua_open来或者lua_State,但是要注意这里只是个宏。 luaopen_base()打开基本的库。 tolua_classgroup_open是tolua+生成的函数,用来向lua导出你定义的类和其它变量及函数。 luaL_dofile也是宏定义,用来加载并执行一个脚本文件,在lauxlib.h中定义。 lua_close关闭之前打开的状态块。 关于这些函数的详细说明,请参考lua5.1在线文档。 下面是classgroup.lua文件: print(now in classgroup.lua!) print(get the CTestSystem singleton, call GetNumberObj and GetMessageObj:) singleton = CTestSystem:GetSingleton(); print(singleton) numobj = singleton:GetNumberObj(); print(numobj) msgobj = singleton:GetMessageObj(); print(msgobj) -access CNumber and CMessage print(init numobjs number: .numobj:GetNumber(); numobj:SetNumber(100); print(after call numobj:SetNumber(100), changed number : .numobj:GetNumber() print(init msgobjs message: .msgobj:GetMessage();msgobj:SetMessage(This message is set in lua script); print(new message: .msgobj:GetMessage() msgobj:ShowMessage() OK,这是个简单的例子,我们只用到了tolua+最基本的东西,进一步的研究学习可以琢磨它的文档。但是我用luaplus想做到这一点,费了不少力 气。相对luaplus,tolua+在导出类到lua方面更为方便好用,而luaplus用来访问lua脚本则比tolua+方便(隔离了繁琐的虚 拟栈操作)。两个封装的侧重点不同,如果可以结合起来,会非常有趣,双向的访问都很方便。有时间的话我会尝试一下。 接下来会试验一下单继承。 =*= 刚才试验了下$renaming 可以用。在pkg后加入$renaming CTestSystem lSystems,用tolua+编译,然后编译工程,则必须修改classgroup.lua,将singleton = CTestSystem:GetSingleton();改为singleton = lSystems:GetSingleton();。tolua+初探(五)(转)2010-01-29 10:25 这个,tolua+支持采用了单继承的类的直接导出,在lua中可以像在C+中那样访问基类的方法。和其它简单类的导出没什么区别。 只是个简单的示例,我们定义一个控件基类,从它派生一个按钮类。然后在lua中分别访问基类和按钮类的方法。我们导出一个全局变量lbutton,同时也在lua中生成一个新button。 先看实际的头文件inheritance.h,我把实现也写在了头文件里。 #ifndef _CLASS_INHERITANCE_H #define _CLASS_INHERITANCE_H #define WIN32_LEAN_AND_MEAN #include #include typedef enum . AUICSNormal = 0, AUICSHover = 1, AUICSPushed = 2, AUICSDisabled = 3, AUICSHide = 4, AUICSFORCEDOWRD = 0xFFFFFFFF AUIControlState; class CAUIControl . public: /should not be called from lua scripts CAUIControl() :m_nID(-1), m_state(AUICSNormal), m_bVisible(true), m_bEnable(true), m_fAlpha(0.0f),m_strText() virtual CAUIControl(). public: /tolua void SetID(int nID). m_nID = nID; int GetID(). return m_nID; void SetText(char * szText). m_strText = szText; const char * GetText(). return m_strText.c_str(); void SetPosition(POINT pt). m_position = pt; POINT GetPosition(). return m_position; void SetSize(SIZE sz). m_size = sz; SIZE GetSize(). return m_size; void SetVisible(bool bVisible). m_bVisible = bVisible; bool IsVisible(). return m_bVisible; void SetEnabled(bool bEnable). m_bEnable=bEnable; bool IsEnabled(). return m_bEnable; void SetAlpha(float fAlpha). m_fAlpha=fAlpha; float GetAlpha(). return m_fAlpha; public: /should not be called from lua scriptsvirtual void Render() = 0; virtual bool MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam).return false;protected: int m_nID; AUIControlState m_state; bool m_bVisible;bool m_bEnable; POINT m_position;SIZE m_size;float m_fAlpha; std:string m_strText; ;class CAUIButton : public CAUIControl . public: CAUIButton():m_pTexture(NULL) . virtual CAUIButton(). public:void SetTexture(char * szFile). void SetTextureRects(const RECT & rcNormal, const RECT &rcHover, const RECT &rcPushed, const RECT& rcDisabled). void SetAlpha(float fAlpha). m_fAlpha = fAlpha; printf(CAUIButton:SetAlpha, extra process here!); public:void Render().printf(CAUIButton:Render ); bool MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam). printf(CAUIButton:MsgProc );return false; protected: void * LoadTexture(char * szTextureFile).return NULL; void * m_pTexture; RECT m_rects4; ; extern CAUIButton g_button; #endif g_button的实例定义在main函数所在的文件中。 下面是inheritance.pkg文件: $#include inheritance.h class CAUIControl . public: /tolua void SetID(int nID); int GetID(); void SetText(char * szText); const char * GetText(); void SetPosition(POINT pt); POINT GetPosition(); void SetSize(SIZE sz); SIZE GetSize(); void SetVisible(bool bVisible); bool IsVisible(); void SetEnabled(bool bEnable); bool IsEnabled(); void SetAlpha(float fAlpha); float GetAlpha(); ; class CAUIButton : public CAUIControl . public: CAUIButton(); virtual CAUIButton(); public: void SetTexture(char * szFile); void SetTextureRects(const RECT & rcNormal, const RECT &rcHover, const RECT &rcPushed, const RECT& rcDisabled); void SetAlpha(float fAlpha); ; extern CAUIButton g_buttonlbutton; 对于基类CAUIControl,只导出部分方法,不导出构造函数,不允许在Lua中直接生成其实例。派生类CAUIButton可以在lua中生成实 例。CAUIButton重写了基类的SetAlpha函数也增加了一些新的函数,如设置纹理函数SetTexture。 全局变量的导出很简单,extern CAUIButton g_buttonlbutton;一个语句就可以了。我们还可以为其加上tolua_readonly修饰符。我把它重名为lbutton。 好了,下面用tolua+.exe生成inherit.cpp文件: tolua+.exe -n inherit -o inherit.cpp inheritance.pkg 接下来是驱动文件inheritance.cpp: #include lua.hpp #include inheritance.h int tolua_inherit_open(lua_State *); CAUIButton g_button; int _tmain(int argc, _TCHAR* argv) . lua_State * L= luaL_newstate(); luaopen_base(L); tolua_inherit_open(L); luaL_dofile(L, .scriptsinheritance.lua); lua_close(L); return 0; tolua+初探(六)(转)2010-01-29 10:25最后是inheritance.lua文件: print(now in inheritance.lua!) -access global button print(global button test) lbutton:SetAlpha(0.5) print(lbutton:GetAlpha() lbutton:SetID(100) lbutton:SetText(global button) print(lbutton:GetText() -alloc new button newbutton = CAUIButton:new() -CAUIControl s methods newbutton:SetID(101) print(newbutton:GetID() newbutton:SetText(new button) print(newbutton:GetText() -CAUIButtons SetAlpha newbutton:SetAlpha(0.7) print(newbutton:GetAlpha() 大功告成了,几乎没有任何新意。不过还是验证了一点东西,仅此而已。 接下来要演示如何呼叫lua脚本中的函数,并向其传递参数,在该lua函数中对参数进行类型转换,然后呼叫其特定方法。tolua+初探(七)(转)2010-01-29 10:35这是学习tolua+的最后一篇了。在这一篇里完成一个稍微复杂一点的例子(_其实还是很简单)。 导出三个类CBase、CDerived1、CDerived2到lua,导出两个函数toDerived1、toDerived2。lua脚本中声明两 个函数Derived1Test和Derived2Test,我们在C+中调用。Derived1Test和Derived2Test会调用 toDerived*对其参数进行向下转换(从CBase转到CDerived*),然后调用派生类的方法做一些测试。 基本上和前面几个例子类似,新增加的部分是在C+中调用Lua脚本里定义的函数。这牵涉到虚拟栈的操作,后面会解释一下。 还是老样子,先把实际的头文件列出来。tlclass.h如下: #ifndef _TOLUACLASS_h #define _TOLUACLASS_h class CBase public: CBase()virtual CBase() virtual void ShowMessage()printf(BaseClass );static char * ClassName() return CBase; ; class CDerived1 : public CBase public: CDerived1()CDerived1()void ShowMessage()printf(Derived1Class );void ShowDerived1()printf(show derived11111 ); class CDerived2 : public CBasepublic: CDerived2()m_nNumber=0; CDerived2() void ShowMessage()printf(Derived2Class );void ShowDerived2()printf(show derived22222 ); void SetNumber(int num) m_nNumber = num; int GetNumber() return m_nNumber; protected: int m_nNumber; ; extern CDerived1 * toDerived1(void * p); extern CDerived2 * toDerived2(void * p); #endif tlclass.pkg如下: $#include tlclass.hclass CBasepublic:virtual void ShowMessage(); static char * ClassName();class CDerived1 : public CBase public:void ShowMessage(); void ShowDerived1(); ;class CDerived2 : public CBase public:void ShowMessage(); void ShowDerived2(); void SetNumber(int num); int GetNumber(); ;CDerived1 * toDerived1(void * p); CDerived2 * toDerived2(void * p);tolua+初探(八)(转)2010-01-29 10:42这次多定义了两个函数toDerived1和toDerived2,全局的。我们也可以把他们直接放在类中,或者一个MODULE中。module大概是 类似的namespace的东西,把一堆杂七杂八的家什如变量、常量、函数、类实例等放在一起,在lua中通过.来访问。下面是手册中的例子: module mod #define N extern int var; int func (.): 这样我们可以在lua中用mod.N,mod.var,mod.func来访问其成员。 原本toDerived*的参数是CBase*,但是从C+向Lua函数传参数的时候我调用了lua_pushlightuserdata,结果在脚本 中报错,说toDerived*应当接受CBase*而非userdata。于是干脆把参数修改成void*,这下lua不再叫唤了。 好了,到了列出驱动文件的时候了。CallLuaFunc.cpp: #include lua.hpp #include tlclass.h CDerived1 * toDerived1(void * p)return dynamic_cast(CBase*)p); CDerived2 * toDerived2(void * p)return dynamic_cast(CBase*)p); int tolua_calllua_open(lua_State*); int _tmain(int argc, _TCHAR* argv) lua_State * L = luaL_newstate(); luaopen_b
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 融城医院笔试题目及答案
- 金融业务知识综合测试卷含英文释义读音试卷及答案
- 2025年旅游合同范本修订
- 2025年房地产客户情绪调研合同协议
- 2025年房产直播平台服务合同协议
- 2025年防汛应急预案评估协议合同
- 2025年二手游戏卡密交易合同协议
- 2025年电工证考试模拟试题及答案
- 外卖评审面试题及答案
- 团委竞聘面试题及答案
- 云南省国省干线公路养护管理模式优化:基于公路局视角的深度剖析与创新路径
- 英语数字教学课件
- 贫血护理查房课件
- (人教A版)必修一高一数学上册期中模拟卷01(解析版)
- 胸痛患者转运课件
- 基于PLC技术的电动汽车充电系统设计
- 2025-2026学年教科版(2024)小学科学三年级上册(全册)每课教学反思
- 办理诈骗案件汇报
- GB 21256-2025粗钢生产主要工序单位产品能源消耗限额
- 2025年《临床输血技术规范》
- 2025年仓储员笔试题库及答案
评论
0/150
提交评论