加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Lua脚本学习

发布时间:2020-12-14 22:20:06 所属栏目:大数据 来源:网络整理
导读:LUA脚本学习 从lua调用C++函数和对象 ??? 利用LuaPlus可以方便的从C++中调用lua脚本,翻过也一样。通过注册函数或类对象,lua便可以访问C++。? ???? 一、C风格函数注册 ??? Lua提供了C风格的回调函数注册,该函数原型如下: ??? int Callback(LuaState* stat

LUA脚本学习

从lua调用C++函数和对象
??? 利用LuaPlus可以方便的从C++中调用lua脚本,翻过也一样。通过注册函数或类对象,lua便可以访问C++。?
????
一、C风格函数注册
??? Lua提供了C风格的回调函数注册,该函数原型如下:
??? int Callback(LuaState* state);
????
??? 无论是全局函数、类非虚函数、类虚函数,只要符合上面的原型,都可以向Lua注册。我们以全局函数为例,下面是我们提供的一个回调函数CStyleAddFunc:

int CStyleAddFunc(LuaState * state)?
{??? LuaStack args(state);
????? if( args[1].IsNumber() && args[2].IsNumber() )
????? {??? state->PushNumber(args[1].GetInteger() + args[2].GetInteger());
?????????? return 1;?????
????? }?????
????? return 0;?
}


??? 在回调函数中,我们通过栈来访问参数,栈中可以存贮多个参数,LuaStack args(state);语句获取栈对象供后续访问。???? 接下来判断参数是否是数字,如果两个参数都是数字,那么进行加操作,将结果压入栈中,将压入栈中的数据的个数返回。注意,返回值代表压入栈中的元素的个数,而不是某种计算结果或其它意义的返回值。通过改变返回值来查看程序的输出,这样可以对返回值的含义有个感性的了解。???? 要注册回到只需调用Register函数即可,这在第一篇中已经用到。下面是测试函数:

void TestCFunctionCallBack()?
{
?? LuaStateOwner state;????? //"print" need this
?? state->OpenLibs();????? //register my function CStyleAddFunc to Add
?? state->GetGlobals().Register("Add",CStyleAddFunc);????? //call my function and print the result???
?? state->DoString("ret = Add(1,5);print(ret)");?
}

?? state->DoString("ret = Add(1,5); print(ret)");该句用来从执行Lua命令串。我们先调用Add并将结果赋值给ret变量,然后打印ret的值。 main函数如下:?

int _tmain(int argc,_TCHAR* argv[])?
{????
?? TestCFunctionCallBack();???
?? return 0;
}

?? 编译运行,一切OK。???? 我们也可以从Lua脚本文件中调用注册的回调函数,第一篇中有演示。???? 要注册类的成员函数,则需要调用Register的另一种形式Register( const char* funcName,const Callee& callee,int (Callee::*func)(LuaState*),int nupvalues = 0 );,提供类实例指针和函数即可完成注册。下面是示例代码:

class CTestCallBack?
{?
public:?
?? int NonVirtualFunc(LuaState *state)?????
?? {???
??? LuaStack args(state);?????
??? printf("In non-virtual member function. no msg. ");????
??? return 0;
?? }????
??
?? int virtual VirtualFunc(LuaState *state)????
?? {
??? LuaStack args(state);?????
??? printf("In virtual member function.msg=%s ",args[1].GetString());??????
??? return 0;
?? }
};?

void TestClassMemberFuncReg()?
{????
?? LuaStateOwner state;????? //"print" need this????
?? state->OpenLibs();???
?? LuaObject globalobj = state->GetGlobals();?
?? CTestCallBack tcb;????
?? globalobj.Register("MemberFunc",tcb,&CTestCallBack::NonVirtualFunc);????
?? state->DoString("MemberFunc()");????
?? globalobj.Register("VirMemberFunc",&CTestCallBack::VirtualFunc);????
?? state->DoString("VirMemberFunc('Hi,myboy')");?
}


修改一下main函数,将TestClassMemberFuncReg()加进去就可以看效果了。

?

二、任意形式C++函数注册
??? LuaPlus提供了 RegisterDirect() 来直接注册任意形式的函数,这样更为直接,不必受限于上述的函数原型,使用起来很方便。同样此函数像Register一样,可以注册类的成员函数(也需要显示指定this指针)。下面是代码:

float Add(float num1,float num2) 
{     
return num1 + num2; 
}
class CForRegDirect
{ 
public:
int Sum(int a,int b,int c)    
{
     return a+b+c;
}      //const is necessary
virtual void SeeMessage(const char *msg)     
{
     printf("msg=%s ",msg);
}
};
void TestRegisterDirect() 
{
LuaStateOwner state;
state->OpenLibs();
LuaObject gobj = state->GetGlobals();        //register global function directly     
gobj.RegisterDirect("Add",Add);     
state->DoString("print(Add(1.5,2.3))");      //register memberfunction     
CForRegDirect forobj;     
gobj.RegisterDirect("MemberSum",forobj,CForRegDirect::Sum);     
state->DoString("print(MemberSum(1,2,7))");      
gobj.RegisterDirect("VirCMsg",CForRegDirect::SeeMessage);     
state->DoString("print(VirCMsg('haha,Do you see me?'))");
}



三、注册函子对象
??? 上面两节的方式可以实现简单的回调注册,注册类的成员函数时需要显式提供类指针,不适合用于映射C++中的类结构。???? RegisterObjectFunctor()和元表(metatable)结合,提供了一种新的方法。我们不需要在注册函数时显式的提供this指针,作为替代,this指针可以从调用者的userdata或__object成员获取。???? 元表(metatable)是一个普通的表对象,它定义了一些可以被重写的操作,如add,sub,mul,index,call等,这些操作以"__"开头,如__add,__index等。加入你重写了__add,那么在执行add操作时就会调用你自己定义的__add操作。这种特性可以用来模拟C++中的类对象,注册函子对象正是利用了这种特性来实现的。???? 下面我们将一个C++类映射到Lua中。类代码如下:

class CMultiObject 
{ 
public:
   CMultiObject(int num) :m_num(num)
   {     }
  
   int Print(LuaState* state)
   {
    printf("%d ",m_num);
    return 0; 
   } 
protected:    
   int m_num; 

}; 
void TestRegObjectDispatchFunctor()
{
   LuaStateOwner state;
   state->OpenLibs();      //create metaTable

   LuaObject metaTableObj = state->GetGlobals().CreateTable("MultiObjectMetaTable"); 
   metaTableObj.SetObject("__index",metaTableObj);     //register functor for multiobject 
   metaTableObj.RegisterObjectFunctor("Print",CMultiObject::Print);      //get a instances of CMultiObject

   CMultiObject obj1(10);     //"clone" a object in lua,the lua object(here is table) has obj1's data 
   LuaObject obj1Obj = state->BoxPointer(&obj1);     //set lua object's metatable to MetaTableObj   
   obj1Obj.SetMetaTable(metaTableObj);     //put lua object to Global scope,thus it can be accessed later. 
   state->GetGlobals().SetObject("obj1",obj1Obj);   

   CMultiObject obj2(20); 
   LuaObject obj2Obj = state->BoxPointer(&obj2);     
   obj2Obj.SetMetaTable(metaTableObj); 
   state->GetGlobals().SetObject("obj2",obj2Obj);      //now call Print and Print2     
   state->DoString("obj1:Print();"); 
   state->DoString("obj2:Print();");
}


????首先我们需要生成一个元表(metatable),将C++类的成员函数注册到该元表中。然后依据CMultiObject的实例生成lua中与其对应的对象(也是表),将该对象的metatable(也即该表的__object成员)设置为之前产生的元表。最后将新生成的lua对象放置到全局作用域中,这样后面就可以直接引用这些对象。???? 我们可以做这样的近似理解:每个实例的数据元素存放在与已对应的lua table中,而类的成员函数则存放在metatable中(函子对象)。当调用obj1obj:Print()时,会先找到其metatable,然后在metatable中找Print()函数。???? 这样便实现了类似C++中的类结构。每个实例有自己的数据,而所有实例共享一份方法列表。???????? 另外一种方式是利用表的userdata来实现,需要先创建一个lua表对象,然后将C++对象obj1设置为该表的userdata(也是设置其__object成员),再将该表对象的metatable设置为我们之前创建的元表。最后就可以用表明来调用Print函数。代码如下:
????
LuaObject table1Obj = state->GetGlobals().CreateTable("table1");
table1Obj.SetLightUserData("__object",&obj1);???
table1Obj.SetMetaTable(metaTableObj);????
LuaObject table2Obj = state->GetGlobals().CreateTable("table2");?
table2Obj.SetLightUserData("__object",&obj2);???
table2Obj.SetMetaTable(metaTableObj);???
state->DoString("table1:Print()");?
state->DoString("table2:Print()");

注册函子对象(RegisterObjectFunctor)这种方式的限制在于:要注册的函数必须符合原型(int Callback(LuaState* state);)。为了打破这种限制,LuaPlus提供了另外一种方式。
????
????
????
四、直接注册函子对象

??? 直接注册函子对象(RegisterObjectDirect)和RegisterDirect类似,不考虑函数原型,可以直接向元表注册任意形式的函数。???? 为CMultiObject添加新的成员函数:
????
void Print2(int num)???
{????????
?? printf("%d %dn",m_num,num);???
}???

调用RegisterObjectDirect方法:?
metaTableObj.RegisterObjectDirect("Print2",(CMultiObject*)0,&CMultiObject::Print2);?

第二个参数(CMultiObject*)0有点奇怪,这是模板参数的需要。?
????
最后:???
state->DoString("obj1:Print2(5)");????
state->DoString("obj2:Print2(15)");???
state->DoString("table1:Print2(5)");?????
state->DoString("table2:Print2(15)");

五、注销回调

??? 注销回调是件简单的事情,调用SetNil("yourCallBack")即可,如:?
gobj.SetNil("Add");
metaTableObj.SetNil("Print2");?

好了,迄今为止最长的一篇,看着像是LuaPlus文档的翻译(?),不过还是加入了一些自己的理解。文档我看了下,琢磨了半天才明白。希望能快点将LuaPlus用起来。?
资料:???? (1)Lua5.1参考手册???? (2)Lua入门wiki???? (3)LuaPlus.html,源码包中带的。

转载自http://hi.baidu.com/li9chuan/blog/item/e65e1d6dc0bd79f642169461.html

参考:http://gpwiki.org/index.php/Scripting_with_LuaPlus_and_Cpp? 简单的LUA脚本编写
????????????http://wwhiz.com/LuaPlus/LuaPlus.html
????????????http://www.cppblog.com/iwangchuchu/default.html?page=2

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
引擎中的简单应用:
void CAICharacterCore::LoadLuaScript( const char* LuaFileName )
{


    try
    {
     //LuaScript->GetGlobals().RegisterDirect( "Thinking",*this,&CAICharacterCore::Thinking );

     //////////////////////////////////////////////////////////////////////////

     LuaObject metaTableObj = m_LuaScript->GetGlobals().CreateTable("MultiObjectMetaTable");
     metaTableObj.SetObject("__index",metaTableObj);
     //metaTableObj.RegisterObjectFunctor( "ClearMoveStep",&CAICharacterCore::ClearMoveStep );
     //metaTableObj.RegisterObjectFunctor( "RestoreHPInstant",&CAICharacterCore::RestoreHPInstant );
     //metaTableObj.RegisterObjectDirect( "SetSayTimeInterval",(CAICharacterCore*)0,&CAICharacterCore::SetSayTimeInterval );


     metaTableObj.RegisterObjectDirect( "LoseHPInstant",&CAICharacterCore::LoseHPInstant );
     metaTableObj.RegisterObjectDirect( "LoseMPInstant",&CAICharacterCore::LoseMPInstant );
     metaTableObj.RegisterObjectDirect( "RestoreHPInstant",&CAICharacterCore::RestoreHPInstant );
     metaTableObj.RegisterObjectDirect( "RestoreMPInstant",&CAICharacterCore::RestoreMPInstant );
     metaTableObj.RegisterObjectDirect( "GetHP",&CAICharacterCore::GetHP );
     metaTableObj.RegisterObjectDirect( "GetMP",&CAICharacterCore::GetMP );
     metaTableObj.RegisterObjectDirect( "GetHPMax",&CAICharacterCore::GetHPMax );
     metaTableObj.RegisterObjectDirect( "GetMPMax",&CAICharacterCore::GetMPMax );
     metaTableObj.RegisterObjectDirect( "UseSkill",&CAICharacterCore::UseSkill );
     metaTableObj.RegisterObjectDirect( "Say",&CAICharacterCore::Say );
     metaTableObj.RegisterObjectDirect( "SayAdvance",&CAICharacterCore::SayAdvance );
     metaTableObj.RegisterObjectDirect( "GetRand",&CAICharacterCore::GetRand );
     metaTableObj.RegisterObjectDirect( "GetLevel",&CAICharacterCore::GetLevel );
     metaTableObj.RegisterObjectDirect( "DropItemRand",&CAICharacterCore::DropItemRand );
     metaTableObj.RegisterObjectDirect( "AddTimer",&CAICharacterCore::AddTimer );
     metaTableObj.RegisterObjectDirect( "GetTimer",&CAICharacterCore::GetTimer );
     metaTableObj.RegisterObjectDirect( "GetTargetHP",&CAICharacterCore::GetTargetHP );
     metaTableObj.RegisterObjectDirect( "GetTargetMP",&CAICharacterCore::GetTargetMP );
     metaTableObj.RegisterObjectDirect( "GetTargetHPMax",&CAICharacterCore::GetTargetHPMax );
     metaTableObj.RegisterObjectDirect( "GetTargetMPMax",&CAICharacterCore::GetTargetMPMax );
     metaTableObj.RegisterObjectDirect( "GetTargetLevel",&CAICharacterCore::GetTargetLevel );
     metaTableObj.RegisterObjectDirect( "GetTargetEnmity",&CAICharacterCore::GetTargetEnmity );
     metaTableObj.RegisterObjectDirect( "SetTargetEnmity",&CAICharacterCore::SetTargetEnmity );
        metaTableObj.RegisterObjectDirect( "GetTargetDistance",&CAICharacterCore::GetTargetDistance );
        metaTableObj.RegisterObjectDirect( "SetArray",&CAICharacterCore::SetArray );
     metaTableObj.RegisterObjectDirect( "GetArray",&CAICharacterCore::GetArray );
     metaTableObj.RegisterObjectDirect( "SetBoolArray",&CAICharacterCore::SetBoolArray );
     metaTableObj.RegisterObjectDirect( "GetBoolArray",&CAICharacterCore::GetBoolArray );


     metaTableObj.RegisterObjectDirect( "SelfMurder",&CAICharacterCore::SelfMurder );

     //metaTableObj.RegisterObjectDirect( "GetTargetName",&CAICharacterCore::GetTargetName );

     LuaObject CAICharacterCoreObj = m_LuaScript->BoxPointer(this);

     CAICharacterCoreObj.SetMetaTable(metaTableObj);

     m_LuaScript->GetGlobals().SetObject( "AI",CAICharacterCoreObj );

     if( !m_LuaScript->LoadFile( LuaFileName ) )
     {
      m_bLuaScriptLoaded = true;
      m_LuaScript->Call( 0,0 );
     }

     //LuaStateOwner LuaScript;
     //LuaScript->LoadFile( "D:/ArenWorkstation/XSanguoRun/Server/Script/AI/test.lua" );
     //LuaObject luaFun = LuaScript->GetGlobal( "Event_OnInit" );

     //if( luaFun.IsFunction() )
     //{
     // int y = 0;
     //}

     //m_LuaScript->DoString("print(obj1:ClearMoveStep())");
     //LuaScript->LoadFile( "D:/ArenWorkstation/XSanguoRun/Server/test.lua" );
    }
    catch (LuaPlus::LuaException &e)
    {
        char szErr[1024] = {0};
        _snprintf(szErr,sizeof(szErr)-1,"怪物 %s AI脚本载入错误: %s",m_data.szCharacterName,e.GetErrorMessage());
        GetErrorLog()->logString(szErr);
        m_bLuaScriptLoaded = false;
    }

}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读