Cocos2d-x之LUA脚本引擎深入分析

Cocos2d-x之LUA脚本引擎深入分析


 

 另:本章所用Cocos2d-x版本为:

Cocos2d-2.0.2

http://cn.cocos2d-x.org/download

         大家好,又是一周过去了,这一周忙的有点焦头烂额,除了工作照例每天加班到九点外,工具箱又做了大幅改进,新的论坛游戏兔子game2z也上线了,Cocos2d-x的学习时间被压缩的很少了,现在是凌晨一点零六分,看着妻子睡熟的样子,我也只能告诉自已,坚持到底。

 

         好了,不说废话,本周奉上一篇初级入门教程博文,Cocos2d-x中的LUA引导与入门。

做为惯例,一切都是以HelloWorld的样例为准。我们今天学习用LUA来完成一版HelloWorld。

 

         大家既使没有看过我的“HelloWorld 深入分析”一文,想必也无数次运行过Cocos2d-x里的HelloCpp工程,对于运行的结果画面熟烂于心。我们回想一下,这个画面里有什么。嗯,一个背景图精灵,一个文字标签,一个关闭按钮。OK,咱们就做这么个东西。

 

         首先,我们要知道LUA是个什么东西,至于官方怎么说可以百度去查,但我想告诉你的是LUA就是一种可以在不必修改C++代码的情况下实现逻辑处理的手段。稍微讲的再明白一点,就是你用指定语法写一些逻辑处理函数然后保存成文本格式,这个文件称为脚本文件,可以被游戏执行。经过若干年的发展,现在在LUA中写逻辑,除了调用注册到LUA的静态C函数外,也已经可以方便的访问到C++工程中的类的成员函数。这是游戏开发史上最重要的技术之一。其改变了很多设计方案,使游戏变的灵活强大而极具扩展性。

 

         在Cocos2d-x中,有两个类来完成对于LUA脚本文件的处理。

 

1. CCLuaEngine:LUA脚本引擎

 

2. CCScriptEngineManager:脚本引擎管理器。

 

 

CCLuaEngine类的基类是一个接口类,叫做CCScriptEngineProtocol,它规定了所有LUA引擎的功能函数,它和CCScriptEngineManager都存放在libcocos2d下的script_support目录中的CCScriptSupport.h/cpp中。

 

首先我们来看一下CCScriptEngineProtocol:


[cpp]  view plain  copy
  1. class CC_DLL CCScriptEngineProtocol : public CCObject  
  2. {  
  3. public:  
  4.     //取得LUA的全局指针,所有的LUA函数都需要使用这个指针来做为参数进行调用。  
  5.     virtual lua_State* getLuaState(void) = 0;  
  6.       
  7.     //通过LUA脚本ID移除对应的CCObject  
  8.     virtual void removeCCObjectByID(int nLuaID) = 0;  
  9.       
  10.     //通过函数索引值移除对应的LUA函数。  
  11.     virtual void removeLuaHandler(int nHandler) = 0;  
  12.       
  13.     //将一个目录中的LUA文件加入到LUA资源容器中。  
  14.     virtual void addSearchPath(const char* path) = 0;  
  15.       
  16.     //执行一段LUA代码  
  17.     virtual int executeString(const char* codes) = 0;  
  18.       
  19.     //执行一个LUA脚本文件。  
  20.     virtual int executeScriptFile(const char* filename) = 0;  
  21.       
  22.     //调用一个全局函数。  
  23.     virtual int executeGlobalFunction(const char* functionName) = 0;  
  24.       
  25. //通过句柄调用函数多种形态。  
  26. //通过句柄调用函数,参数二为参数数量。  
  27. virtual int executeFunctionByHandler(int nHandler, int numArgs = 0) = 0;  
  28. //通过句柄调用函数,参数二为整数数据。  
  29. virtual int executeFunctionWithIntegerData(int nHandler, int data) = 0;  
  30. //通过句柄调用函数,参数二为浮点数据。  
  31. virtual int executeFunctionWithFloatData(int nHandler, float data) = 0;  
  32. //通过句柄调用函数,参数二为布尔型数据。  
  33. virtual int executeFunctionWithBooleanData(int nHandler, bool data) = 0;  
  34. //通过句柄调用函数,参数二为CCObject指针数据和其类型名称。  
  35. virtual int executeFunctionWithCCObject(int nHandler, CCObject* pObject, const char* typeName) = 0;      
  36.   
  37. //将一个整数数值压栈做为参数。  
  38. virtual int pushIntegerToLuaStack(int data) = 0;  
  39. //将一个浮点数值压栈做为参数。  
  40. virtual int pushFloatToLuaStack(int data) = 0;  
  41. //将一个布尔数值压栈做为参数。  
  42. virtual int pushBooleanToLuaStack(int data) = 0;  
  43. //将一个CCObject指针和类型名压栈做为参数。  
  44.     virtual int pushCCObjectToLuaStack(CCObject* pObject, const char* typeName) = 0;  
  45.       
  46.     // 执行单点触屏事件  
  47. virtual int executeTouchEvent(int nHandler, int eventType, CCTouch *pTouch) = 0;  
  48. //执行多点触屏事件。  
  49.     virtual int executeTouchesEvent(int nHandler, int eventType, CCSet *pTouches) = 0;  
  50.     // 执行一个回调函数。  
  51.     virtual int executeSchedule(int nHandler, float dt) = 0;  
  52. };  

这个接口类的功能函数的具体实现,我们要参看CCLuaEngine类。

现在我们打开CCLuaEngine.h:

[cpp]  view plain  copy
  1. //加入lua的头文件,约定其中代码使用C风格  
  2. extern "C" {  
  3. #include "lua.h"  
  4. }  
  5.   
  6. //相应的头文件。  
  7. #include "ccTypes.h"  
  8. #include "cocoa/CCObject.h"  
  9. #include "touch_dispatcher/CCTouch.h"  
  10. #include "cocoa/CCSet.h"  
  11. #include "base_nodes/CCNode.h"  
  12. #include "script_support/CCScriptSupport.h"  
  13.   
  14. //使用Cocos2d命名空间  
  15. NS_CC_BEGIN  
  16.   
  17. // 由CCScriptEngineProtocol派生的实际功能类。  
  18.   
  19. class CCLuaEngine : public CCScriptEngineProtocol  
  20. {  
  21. public:  
  22.     //析构  
  23.     ~CCLuaEngine();  
  24.       
  25.     //取得LUA的全局指针,所有的LUA函数都需要使用这个指针来做为参数进行调用。  
  26.     virtual lua_State* getLuaState(void) {  
  27.         return m_state;  
  28.     }  
  29.       
  30.     …此处省略若干字。  
  31.       
  32.     // 加入一个多线程加载LUA脚本的实时回调函数,此函数用于ANDROID  
  33.     virtual void addLuaLoader(lua_CFunction func);  
  34.     //取得当前单件实例指针  
  35.     static CCLuaEngine* engine();  
  36.       
  37. private:  
  38.     //构造,单例,你懂的。  
  39.     CCLuaEngine(void)  
  40.     : m_state(NULL)  
  41.     {  
  42.     }  
  43.     //初始化函数。  
  44. bool init(void);  
  45. //将一个句柄压栈  
  46.     bool pushFunctionByHandler(int nHandler);  
  47.     //唯一的LUA指针  
  48.     lua_State* m_state;  
  49. };  
  50.   
  51. NS_CC_END  

分析其CPP实现:

[cpp]  view plain  copy
  1. //本类的头文件。  
  2. #include "CCLuaEngine.h"  
  3. //这里用到了tolua++库,tolua++库是一个专门处理LUA脚本的第三方库,可以很好的完成LUA访问C++类及成员函数的功能。如果没有tolua++,这块要处理起来可是麻烦死了。  
  4. #include "tolua++.h"  
  5.   
  6. //加入lua库的相应头文件。  
  7. extern "C" {  
  8. #include "lualib.h"  
  9. #include "lauxlib.h"  
  10. #include "tolua_fix.h"  
  11. }  
  12.   
  13. //加入Cocos2d-x所用的相应头文件。  
  14. #include "cocos2d.h"  
  15. #include "LuaCocos2d.h"  
  16. #include "cocoa/CCArray.h"  
  17. #include "CCScheduler.h"  
  18.   
  19. //如果是ANDROID平台,加上对多线程加载LUA脚本的支持,使用相应的头文件。  
  20.   
  21. #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)  
  22. #include "Cocos2dxLuaLoader.h"  
  23. #endif  
  24.   
  25. //开始Cocos2d-x命名空间。  
  26. NS_CC_BEGIN  
  27.   
  28. //析构。  
  29. CCLuaEngine::~CCLuaEngine()  
  30. {  
  31.     //结束对LUA指针的使用,关闭LUA。  
  32.     lua_close(m_state);  
  33. }  
  34.   
  35. //初始始。  
  36. bool CCLuaEngine::init(void)  
  37. {  
  38.     //开始对LUA的使用,创建一个LUA指针。  
  39. m_state = lua_open();  
  40. //打开相应的库。  
  41. luaL_openlibs(m_state);  
  42. //打开使用tolua封装的访问Cocos2d-x的库。  
  43.     tolua_Cocos2d_open(m_state);  
  44. tolua_prepare_ccobject_table(m_state);  
  45. //如果是ANDROID平台,也加上对LUA进行多线程加载的库支持。  
  46. #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)  
  47.     addLuaLoader(loader_Android);  
  48. #endif  
  49.     return true;  
  50. }  
  51.   
  52. //取得单例指针。  
  53. CCLuaEngine* CCLuaEngine::engine()  
  54. {  
  55.     CCLuaEngine* pEngine = new CCLuaEngine();  
  56.     pEngine->init();  
  57.     pEngine->autorelease();  
  58.     return pEngine;  
  59. }  
  60.   
  61. //通过LUA脚本ID移除对应的CCObject   
  62. void CCLuaEngine::removeCCObjectByID(int nLuaID)  
  63. {  
  64.     tolua_remove_ccobject_by_refid(m_state, nLuaID);  
  65. }  
  66. //<span style="font-family: Arial, Helvetica, sans-serif;">通过函数索引值移除对应的LUA函数。</span>  
  67. void CCLuaEngine::removeLuaHandler(int nHandler)  
  68. {  
  69.     tolua_remove_function_by_refid(m_state, nHandler);  
  70. }  
  71. //将一个目录中的LUA文件加入到LUA资源容器中。  
  72. void CCLuaEngine::addSearchPath(const char* path)  
  73. {  
  74.     //取得全局表package  
  75. lua_getglobal(m_state, "package");                                
  76. //取得其中的path字段,压入栈顶。  
  77. lua_getfield(m_state, -1, "path");              
  78. //取得当前的目录字符串。  
  79. const char* cur_path =  lua_tostring(m_state, -1);  
  80. //参数出栈,恢复堆栈。  
  81. lua_pop(m_state, 1);                                              
  82. //将新路径字符串加入到路径串列中,压入栈顶。  
  83. lua_pushfstring(m_state, "%s;%s/?.lua", cur_path, path);  
  84. //设置path字段值路径  
  85. lua_setfield(m_state, -2, "path");        
  86. //参数出栈,恢复堆栈。  
  87.  lua_pop(m_state, 1);                                              
  88. }  
  89. //执行一段LUA代码  
  90. int CCLuaEngine::executeString(const char *codes)  
  91. {  
  92.     //执行一段LUA代码。返回值存放到nRet中。  
  93. int nRet =    luaL_dostring(m_state, codes);  
  94. //进行下拉圾收集。  
  95.     lua_gc(m_state, LUA_GCCOLLECT, 0);  
  96.     //如果出错,打印日志。  
  97.     if (nRet != 0)  
  98.     {  
  99.         CCLOG("[LUA ERROR] %s", lua_tostring(m_state, -1));  
  100.         lua_pop(m_state, 1);  
  101.         return nRet;  
  102.     }  
  103.     return 0;  
  104. }  
  105. //执行一个LUA脚本文件。  
  106.   
  107. int CCLuaEngine::executeScriptFile(const char* filename)  
  108. {  
  109.     //执行一个LUA脚本文件。返回值存放到nRet中。  
  110.     int nRet = luaL_dofile(m_state, filename);  
  111. //    lua_gc(m_state, LUA_GCCOLLECT, 0);  
  112.     //如果出错,打印日志。  
  113.     if (nRet != 0)  
  114.     {  
  115.         CCLOG("[LUA ERROR] %s", lua_tostring(m_state, -1));  
  116.         lua_pop(m_state, 1);  
  117.         return nRet;  
  118.     }  
  119.     return 0;  
  120. }  
  121. //调用一个全局函数。  
  122. int    CCLuaEngine::executeGlobalFunction(const char* functionName)  
  123. {  
  124.     //将全局函数放在栈顶  
  125. lua_getglobal(m_state, functionName);  /* query function by name, stack: function */  
  126. //判断是否是函数。  
  127.     if (!lua_isfunction(m_state, -1))  
  128.     {  
  129.         CCLOG("[LUA ERROR] name '%s' does not represent a Lua function", functionName);  
  130.         lua_pop(m_state, 1);  
  131.         return 0;  
  132.     }  
  133.     //调用函数。  
  134.     int error = lua_pcall(m_state, 0, 1, 0);         /* call function, stack: ret */  
  135. //    lua_gc(m_state, LUA_GCCOLLECT, 0);  
  136.   
  137.     if (error)  
  138.     {  
  139.         CCLOG("[LUA ERROR] %s", lua_tostring(m_state, - 1));  
  140.         lua_pop(m_state, 1); // clean error message  
  141.         return 0;  
  142.     }  
  143.   
  144.     // get return value  
  145.     //如果取得的第一个参数不是数字,返回错误。  
  146.     if (!lua_isnumber(m_state, -1))  
  147.     {  
  148.         lua_pop(m_state, 1);  
  149.         return 0;  
  150.     }  
  151.     //取得数字的参数存放在ret中。  
  152. int ret = lua_tointeger(m_state, -1);  
  153. //参数出栈,恢复堆栈。  
  154.     lua_pop(m_state, 1);                                            /* stack: - */  
  155.     return ret;  
  156. }  
  157. //通过句柄调用函数多种形态。  
  158. //通过句柄调用函数,参数二为参数数量。  
  159. int CCLuaEngine::executeFunctionByHandler(int nHandler, int numArgs)  
  160. {  
  161.     if (pushFunctionByHandler(nHandler))  
  162.     {  
  163.         if (numArgs > 0)  
  164.         {  
  165.             lua_insert(m_state, -(numArgs + 1));                        /* stack: ... func arg1 arg2 ... */  
  166.         }  
  167.   
  168.         int error = 0;  
  169.         // try  
  170.         // {  
  171.             error = lua_pcall(m_state, numArgs, 1, 0);                  /* stack: ... ret */  
  172.         // }  
  173.         // catch (exception& e)  
  174.         // {  
  175.         //     CCLOG("[LUA ERROR] lua_pcall(%d) catch C++ exception: %s", nHandler, e.what());  
  176.         //     lua_settop(m_state, 0);  
  177.         //     return 0;  
  178.         // }  
  179.         // catch (...)  
  180.         // {  
  181.         //     CCLOG("[LUA ERROR] lua_pcall(%d) catch C++ unknown exception.", nHandler);  
  182.         //     lua_settop(m_state, 0);  
  183.         //     return 0;  
  184.         // }  
  185.         if (error)  
  186.         {  
  187.             CCLOG("[LUA ERROR] %s", lua_tostring(m_state, - 1));  
  188.             lua_settop(m_state, 0);  
  189.             return 0;  
  190.         }  
  191.   
  192.         // get return value  
  193.         int ret = 0;  
  194.         //如果返回参数是数字转为整数。  
  195.         if (lua_isnumber(m_state, -1))  
  196.         {  
  197.             ret = lua_tointeger(m_state, -1);  
  198.         }//如果是布尔型转为true或false  
  199.         else if (lua_isboolean(m_state, -1))  
  200.         {  
  201.             ret = lua_toboolean(m_state, -1);  
  202.         }  
  203.     //参数出栈,恢复堆栈。  
  204.         lua_pop(m_state, 1);  
  205.         return ret;  
  206.     }  
  207.     else  
  208.     {  
  209.         return 0;  
  210.     }  
  211. }  
  212.   
  213. //通过句柄调用函数,参数二为整数数据。  
  214. int CCLuaEngine::executeFunctionWithIntegerData(int nHandler, int data)  
  215. {  
  216.     lua_pushinteger(m_state, data);  
  217.     return executeFunctionByHandler(nHandler, 1);  
  218. }  
  219. //通过句柄调用函数,参数二为浮点数据。  
  220. int CCLuaEngine::executeFunctionWithFloatData(int nHandler, float data)  
  221. {  
  222.     lua_pushnumber(m_state, data);  
  223.     return executeFunctionByHandler(nHandler, 1);  
  224. }  
  225. //通过句柄调用函数,参数二为布尔型数据。  
  226. int CCLuaEngine::executeFunctionWithBooleanData(int nHandler, bool data)  
  227. {  
  228.     lua_pushboolean(m_state, data);  
  229.     return executeFunctionByHandler(nHandler, 1);  
  230. }  
  231. //通过句柄调用函数,参数二为CCObject指针数据和其类型名称。  
  232. int CCLuaEngine::executeFunctionWithCCObject(int nHandler, CCObject* pObject, const char* typeName)  
  233. {  
  234.     tolua_pushusertype_ccobject(m_state, pObject->m_uID, &pObject->m_nLuaID, pObject, typeName);  
  235.     return executeFunctionByHandler(nHandler, 1);  
  236. }  
  237. //将一个整数数值压栈做为参数。  
  238. int CCLuaEngine::pushIntegerToLuaStack(int data)  
  239. {  
  240.     //将整数值压入堆栈  
  241. lua_pushinteger(m_state, data);  
  242. //返回参数的数量。  
  243.     return lua_gettop(m_state);  
  244. }  
  245. //将一个浮点数值压栈做为参数。  
  246. int CCLuaEngine::pushFloatToLuaStack(int data)  
  247. {  
  248.     //将数字值压入堆栈  
  249. lua_pushnumber(m_state, data);  
  250. //返回参数的数量。  
  251.     return lua_gettop(m_state);  
  252. }  
  253. //将一个布尔数值压栈做为参数。  
  254. int CCLuaEngine::pushBooleanToLuaStack(int data)  
  255. {  
  256.     //将boolean值压入堆栈  
  257. lua_pushboolean(m_state, data);  
  258. //返回参数的数量。  
  259.     return lua_gettop(m_state);  
  260. }  
  261. //将一个CCObject指针和类型名压栈做为参数。  
  262. int CCLuaEngine::pushCCObjectToLuaStack(CCObject* pObject, const char* typeName)  
  263. {  
  264.     tolua_pushusertype_ccobject(m_state, pObject->m_uID, &pObject->m_nLuaID, pObject, typeName);  
  265.     return lua_gettop(m_state);  
  266. }  
  267.   
  268. // 执行单点触屏事件  
  269. int CCLuaEngine::executeTouchEvent(int nHandler, int eventType, CCTouch *pTouch)  
  270. {  
  271. CCPoint pt = CCDirector::sharedDirector()->convertToGL(pTouch->getLocationInView());  
  272. //将参数压栈后调用函数。  
  273.     lua_pushinteger(m_state, eventType);  
  274.     lua_pushnumber(m_state, pt.x);  
  275.     lua_pushnumber(m_state, pt.y);  
  276.     return executeFunctionByHandler(nHandler, 3);  
  277. }  
  278.   
  279. //执行多点触屏事件。  
  280. int CCLuaEngine::executeTouchesEvent(int nHandler, int eventType, CCSet *pTouches)  
  281. {  
  282. //将类型参数压栈后调用函数。  
  283. lua_pushinteger(m_state, eventType);  
  284. //创建一个表  
  285.     lua_newtable(m_state);  
  286. //将多个触点信息参数放入表中。  
  287.     CCDirector* pDirector = CCDirector::sharedDirector();  
  288.     CCSetIterator it = pTouches->begin();  
  289.     CCTouch* pTouch;  
  290.     int n = 1;  
  291.     while (it != pTouches->end())  
  292.     {  
  293.         pTouch = (CCTouch*)*it;  
  294.         CCPoint pt = pDirector->convertToGL(pTouch->getLocationInView());  
  295.         //将位置x压入堆栈  
  296.         lua_pushnumber(m_state, pt.x);  
  297.         //将栈顶的数值放入到表中对应索引n的数值中  
  298.         lua_rawseti(m_state, -2, n++);  
  299.         //将位置x压入堆栈  
  300.         lua_pushnumber(m_state, pt.y);  
  301.         //将栈顶的数值放入到表中对应索引n的数值中  
  302.         lua_rawseti(m_state, -2, n++);  
  303.         ++it;  
  304.     }  
  305.     //以表做为第二参数压栈,调用函数。  
  306.     return executeFunctionByHandler(nHandler, 2);  
  307. }  
  308. //通过句柄调用函数,参数二为CCObject指针数据和其类型名称。  
  309. int CCLuaEngine::executeSchedule(int nHandler, float dt)  
  310. {  
  311.     return executeFunctionWithFloatData(nHandler, dt);  
  312. }  
  313. // 加入一个多线程加载LUA脚本的实时回调函数,此函数用于ANDROID  
  314. void CCLuaEngine::addLuaLoader(lua_CFunction func)  
  315. {  
  316.     if (!func) return;  
  317.   
  318. //取得全局表  
  319. lua_getglobal(m_state, "package");                       
  320. //取得全局表中的“loaders”表  
  321.     lua_getfield(m_state, -1, "loaders");                   
  322. //将设定的函数和参数压栈  
  323. lua_pushcfunction(m_state, func);                       
  324. //将参数压栈  
  325.     for (int i = lua_objlen(m_state, -2) + 1; i > 2; --i)  
  326. {  
  327.     //取得原"loaders"表第i-1个参数  
  328.         lua_rawgeti(m_state, -2, i - 1);                                                                                
  329.         //将取出的值放到新"loaders"表中第i个数值  
  330.         lua_rawseti(m_state, -3, i);                        
  331. }  
  332. //将函数设为新"loaders"表的第2个参数  
  333.     lua_rawseti(m_state, -2, 2);                             
  334. //把“loaders” 表放到全局表中  
  335.     lua_setfield(m_state, -2, "loaders");                    
  336.     //参数出栈,恢复堆栈。  
  337.     lua_pop(m_state, 1);  
  338. }  
  339. //将一个句柄压栈  
  340. bool CCLuaEngine::pushFunctionByHandler(int nHandler)  
  341. {  
  342.     //找出注册函数表的第nHandler个数值  
  343. lua_rawgeti(m_state, LUA_REGISTRYINDEX, nHandler);  /* stack: ... func */  
  344. //判断是否是函数。  
  345.     if (!lua_isfunction(m_state, -1))  
  346.     {  
  347.         CCLOG("[LUA ERROR] function refid '%d' does not reference a Lua function", nHandler);  
  348.         lua_pop(m_state, 1);  
  349.         return false;  
  350.     }  
  351.     return true;  
  352. }  


      然后我们来看一下CCScriptEngineManager,这个类被称为脚本引擎管理器,其实很简单,只是用来设定当前项目的唯一正在使用的脚本引擎。也许Cocos2d-x打算用它管理多种类型脚本引擎,比如Python,js等。


[cpp]  view plain  copy
  1. class CC_DLL CCScriptEngineManager  
  2. {  
  3. public:  
  4.     //析构  
  5.     ~CCScriptEngineManager(void);  
  6.     //取得单例指针  
  7.     CCScriptEngineProtocol* getScriptEngine(void) {  
  8.         return m_pScriptEngine;  
  9.     }  
  10.     //设置使用的LUA管理器  
  11. void setScriptEngine(CCScriptEngineProtocol *pScriptEngine);  
  12. //移除使用的LUA管理器。  
  13.     void removeScriptEngine(void);  
  14.     //取得单例指针  
  15. static CCScriptEngineManager* sharedManager(void);  
  16. //销毁单例  
  17.     static void purgeSharedManager(void);  
  18.   
  19. private:  
  20.     //构造,单例,你懂的。  
  21.     CCScriptEngineManager(void)  
  22.     : m_pScriptEngine(NULL)  
  23.     {  
  24.     }  
  25.     //使用的LUA脚本引擎  
  26.     CCScriptEngineProtocol *m_pScriptEngine;  
  27. };  
  28. 其对应的CPP实现:  
  29. //全局唯一的  
  30. static CCScriptEngineManager* s_pSharedScriptEngineManager = NULL;  
  31. //析构  
  32. CCScriptEngineManager::~CCScriptEngineManager(void)  
  33. {  
  34.     removeScriptEngine();  
  35. }  
  36. //设置使用的LUA管理器  
  37. void CCScriptEngineManager::setScriptEngine(CCScriptEngineProtocol *pScriptEngine)  
  38. {  
  39.     removeScriptEngine();  
  40.     m_pScriptEngine = pScriptEngine;  
  41.     m_pScriptEngine->retain();  
  42. }  
  43. //移除使用的LUA管理器。  
  44. void CCScriptEngineManager::removeScriptEngine(void)  
  45. {  
  46.     if (m_pScriptEngine)  
  47.     {  
  48.         m_pScriptEngine->release();  
  49.         m_pScriptEngine = NULL;  
  50.     }  
  51. }  
  52.   
  53. //取得单例指针  
  54. CCScriptEngineManager* CCScriptEngineManager::sharedManager(void)  
  55. {  
  56.     if (!s_pSharedScriptEngineManager)  
  57.     {  
  58.         s_pSharedScriptEngineManager = new CCScriptEngineManager();  
  59.     }  
  60.     return s_pSharedScriptEngineManager;  
  61. }  
  62. //销毁单例  
  63. void CCScriptEngineManager::purgeSharedManager(void)  
  64. {  
  65.     if (s_pSharedScriptEngineManager)  
  66.     {  
  67.         delete s_pSharedScriptEngineManager;  
  68.         s_pSharedScriptEngineManager = NULL;  
  69.     }  
  70. }  

         现在我们来实际操作一下。

         打开HelloLua工程中的AppDelegate.cpp:

在AppDelegate::applicationDidFinishLaunching()函数中看这几行代码:

[cpp]  view plain  copy
  1.  //取得LUA脚本引擎  
  2. CCScriptEngineProtocol* pEngine = CCLuaEngine::engine();  
  3. //设置脚本引擎管理器使用新创建的LUA脚本引擎  
  4.     CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);  
  5. //如果是ANDROID平台,获hello.lua内存到字符串然后执行字符串  
  6. #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)  
  7.     CCString* pstrFileContent = CCString::createWithContentsOfFile("hello.lua");  
  8.     if (pstrFileContent)  
  9.     {  
  10.         pEngine->executeString(pstrFileContent->getCString());  
  11.     }  
  12. #else  
  13.     //如果不是ANDROID平台,取得hello.lua文件全路径并执行文件。  
  14.     std::string path = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath("hello.lua");  
  15.     pEngine->addSearchPath(path.substr(0, path.find_last_of("/")).c_str());  
  16.     pEngine->executeScriptFile(path.c_str());  
  17. #endif   

 

         就这样,hello.lua中的脚本就可以被执行了。

 

         现在我们将HelloLua工程目录拷出一份来,将目录和工程命名为StudyLua,并在程序运行目录中加入相关资源图片。之后我们打开hello.lua:


[html]  view plain  copy
  1. -- 设置内存回收  
  2. collectgarbage("setpause", 100)  
  3. collectgarbage("setstepmul", 5000)  
  4.   
  5.   
  6. -- 取得窗口大小  
  7. local winSize = CCDirector:sharedDirector():getWinSize()  
  8. -- 将Hello背景图加入  
  9.   
  10. local function createLayerHello()  
  11.     local layerHello = CCLayer:create()  
  12.   
  13.     -- 加入背景图  
  14.     local bg = CCSprite:create("Hello.png")  
  15.     bg:setPosition(winSize.width / 2 , winSize.height / 2)  
  16.     layerHello:addChild(bg)  
  17.       
  18.     -- 创建HelloWorld  
  19.     local label = CCLabelTTF:create("Hello Cocos2d-x", "Arial", 50)  
  20.     label:setPosition(winSize.width / 2 ,60)  
  21.     label:setVisible(true)  
  22.     layerHello:addChild(label)  
  23.        
  24.     return layerHello  
  25. end  
  26.   
  27. --将关闭按钮菜单加入  
  28. local function createExitBtn()  
  29.   
  30.     local layerMenu = CCLayer:create()  
  31.   
  32.     --局部函数,用于退出  
  33.     local function menuCallbackExit()  
  34.         CCDirector:sharedDirector():endToLua()  
  35.     end  
  36.   
  37.     -- 创建退出按钮  
  38.     local menuPopupItem = CCMenuItemImage:create("CloseNormal.png", "CloseSelected.png")  
  39.     -- 放在居上角附近  
  40.     menuPopupItem:setPosition(winSize.width - 50, winSize.height - 50)  
  41.     -- 注册退出函数  
  42.     menuPopupItem:registerScriptHandler(menuCallbackExit)  
  43.     -- 由菜单按钮项创建菜单  
  44.     local   menuClose = CCMenu:createWithItem(menuPopupItem)  
  45.     menuClose:setPosition(0, 0)  
  46.     menuClose:setVisible(true)  
  47.     -- 将菜单加入层中  
  48.     layerMenu:addChild(menuClose)  
  49.   
  50.     return layerMenu  
  51. end  
  52.   
  53. --创建场景  
  54. local sceneGame = CCScene:create()  
  55. --将Hello背景图加入  
  56. sceneGame:addChild(createLayerHello())  
  57. --将关闭按钮菜单加入  
  58. sceneGame:addChild(createExitBtn())  
  59. --运行场景  
  60. CCDirector:sharedDirector():runWithScene(sceneGame)  

运行一下:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值