【Cocos2d-x】Lua 资源热更新
前面2篇分别简单介绍 手动bind C++ 类和lua;http://blog.csdn.net/chenee543216/article/details/12074771 使用tolua++简化工作:http://blog.csdn.net/chenee543216/article/details/12172563 这篇简单聊聊 cocos2dx。 一、基本概念 所谓的lua绑定,其实目的就是导出C++的接口给lua,使得在lua中可以操作C++; 而lua和C/C++的唯一官方接口是stack。so,所谓的binding,就是C++,lua双方通过stack交换信息,然后对stack中信息进行解释,并执行相关动作的过程。 1 、 比如lua想生成一个dog 类,则在lua端: local d = Dog:creat(); 这个只是书面形式,其实lua解释器会自动填充stack。 比如,假设这个时候stack内容变成 "creat" "Dog" ......... -- stack bottom 就是说,lua把2个标志入栈,一个是函数名,一个是类名; 在C/C++端,负责绑定的辅助代码(tolua++生成代码+libtolua++,或者我们第一篇文章中的LuaAnimal类)会根据 “Dog"生成一个类,并且根据某个表(见第一篇文章)去调用这个类中于”create“函数对应的函数。 OK,到这里,lua已经调用C、C++完成,并且生成相应的东西。 下面C/C++会把lua需要的返回值再压入stack。 lua端从stack中取出这个值,保留后面使用。 到这里一个完整过程over。 2、 lua端,再次调用 d:sound(); 看官大概已经知道了。lua解释器会把相关信息压入stack,我们可以用第一篇中提供的函数stackDump()来展示stack内容。假设如下: ”sound" "d" 在C++端,取出类实例地址 d,然后根据sound找对应类函数。比如sound00();然后调用d.sound00(); 并且将相关返回值入栈,返回给lua。 3、用完以后gc,大家可以给Dog写个 Dog::~Dog()来看gc信息。 具体过程,给~Dog()下个断点,看C/C++ call stack即可。(我自己偷懒了~) 二、cocos2dx 1、 其实lua和cocos2dx木有啥关系,和cocos2dx sdk发生关系的是tolua++ 生成的C++代码而已。 lua是通过这个中间代码去操作cocos2dx的sdk的。 你实现一个功能,可能要写10几个class,还要调用native code,比如OC、或者java层代码。 但是一旦封装好以后,你使用这个功能只要一个简单调用而已。比如在C++端。我们调用 Money *m = Money::create(); 我们最多只要用到几个public的函数,或者变量。并不关心private的函数和变量,和具体实现。 这个和tolua++的pkg文件编写规则一致。 再啰嗦一点: 比如上面Money类,我们只要 create,count 。。。 几个函数。那么tolua++生成的中间C++代码也只引用到这几个函数。class MMM{ public: int v00001; int v00002; .... int V99999; void f00001(); void f00002() ..... void f99999(); }; 如果,我们在lua中只要调用v0001;和f00001;那么我们的tolua++的pkg只要包括 class MMM{ int v00001; void f00001; }; 即可,大可不必管其它的东西。 2、cocos2dx自己的lua封装,可以到cocos2dx源码目录下面的tools/tolua++去看。 是官方提炼好的pkg,这些pkg最终都被include到Cocos2d.pkg,然后生成一个LuaCocos2d.cpp (见Makefile文件中描述) 这个LuaCocos2d.cpp就是整个cocos2dx中需要被lua使用的接口函数。 二、动手 我们自己写个练手 其实前面都已经写过了:见第二篇文章。唯一不同的是这里新的代码使用到cocos2dx sdk; 如下: NativeHelper.h #ifndef __NativeHelper_H__ #define __NativeHelper_H__ #include "cocos2d.h" USING_NS_CC; class NativeHelper : public cocos2d::CCLayer { public: virtual bool init(); void openURL(std::string url,bool forceCheck=false); CREATE_FUNC(NativeHelper); private: }; #endif NativeHelper.cpp #ifdef ANDROID #include "NativeHelper.h" #include <jni.h> #include "platform/android/jni/JniHelper.h" bool NativeHelper::init() { return true; } void NativeHelper::openURL(std::string url,bool forceCheck) { JniMethodInfo jmi; if(JniHelper::getStaticMethodInfo(jmi,"org/cocos2dx/lib/Cocos2dxActivity","openUrl","([Ljava/lang/String;)V")){ jclass str_cls = jmi.env->FindClass("java/lang/String"); jstring str1 = jmi.env->NewStringUTF(url.c_str()); jstring str2 = jmi.env->NewStringUTF("Nothing ..."); jobjectArray arrs = jmi.env->NewObjectArray(2,str_cls,0); jmi.env->SetObjectArrayElement(arrs,0,str1); jmi.env->SetObjectArrayElement(arrs,1,str2); jmi.env->CallStaticVoidMethod(jmi.classID,jmi.methodID,arrs); } } #endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) #include "NativeHelper.h" bool NativeHelper::init() { return true; } #define kTextFieldTagOfForumPassword 100 //==================================== //typedef void(^AlertBlock)(NSInteger); @interface BlockUIAlertView : UIAlertView { NSString *url; } //@property(nonatomic,copy)AlertBlock block; @property(nonatomic,copy)NSString *url; - (id)initWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle // clickButton:(AlertBlock)_block otherButtonTitles:(NSString *)otherButtonTitles; //-(void)setURL:(NSString*)url; @end @implementation BlockUIAlertView //@synthesize block; @synthesize url; - (id)initWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle // clickButton:(AlertBlock)_block otherButtonTitles:(NSString *)otherButtonTitles { self = [super initWithTitle:title message:message delegate:self cancelButtonTitle:cancelButtonTitle otherButtonTitles:otherButtonTitles,nil]; // if (self) { // self.block = _block; // } return self; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { // self.block(buttonIndex); if (buttonIndex == 1) { CCLOG("------------button canceled"); return; } UITextField *pwdTextField = (UITextField *)[alertView viewWithTag:kTextFieldTagOfForumPassword]; NSString *pwd = [pwdTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; CCLOG("--------------%s",[pwd UTF8String]); if ([pwd caseInsensitiveCompare:@"iamadult"] == NSOrderedSame) { if ([url length]>[@"http://www.1.com" length]) { [[UIApplication sharedApplication]openURL:[NSURL URLWithString:url]]; } } } @end //==================================== void NativeHelper::openURL(std::string url,bool forceCheck) { if (!forceCheck) { NSString * nsurl = [NSString stringWithCString:url.c_str() encoding:[NSString defaultCStringEncoding]]; [[UIApplication sharedApplication]openURL:[NSURL URLWithString:nsurl]]; return; } BlockUIAlertView *alertView = [[BlockUIAlertView alloc] initWithTitle:@"请输入字符: iamadult" message:@"nn" cancelButtonTitle:@"确认" // clickButton:^(NSInteger indexButton){ // if (indexButton == 0) { // CCLOG("You press btn 0"); // }else if(indexButton == 1){ // CCLOG("You press btn 1"); // } // } otherButtonTitles:@"取消"]; [alertView setUrl:[NSString stringWithCString:url.c_str() encoding:[NSString defaultCStringEncoding]]]; UITextField *textFieldPwd = [[UITextField alloc] initWithFrame:CGRectMake(27.0,60.0,230.0,25.0)]; [textFieldPwd setBackgroundColor:[UIColor whiteColor]]; [textFieldPwd setTag:kTextFieldTagOfForumPassword]; [textFieldPwd setPlaceholder:@"请输入密码"]; [alertView addSubview:textFieldPwd]; [textFieldPwd release]; [alertView show]; [alertView release]; } #endif 这3个文件实现一个NativeHelper类,这个类只干一件事:调用系统web浏览器打开一个URL。通过宏定义来控制android和ios的独立实现。(ios端和android端的区别是:ios端打开URL之前会弹出一个对话框,让用户输入验证字符。 just for parent protect ) 我们调用方式简单如下: NativeHelper *nhelper = NativeHelper::create(); const std::string strPrivacy = "http://http://blog.csdn.net/chenee543216/article/details/12172563"; nhelper->openURL(strPrivacy,true); 现在,我们把调用需要的2个函数用tolua++导出给lua,there are create() and openURL() toluaNativeHelper.pkg 1 2 $#include "cocos2d.h" 3 $#include "NativeHelper.h" 4 class NativeHelper : public cocos2d::CCLayer 5 { 6 void openURL(std::string url,bool forceCheck=false); 7 static NativeHelper* create(); 8 }; 9 生成的命令为: tolua++ -o toluaNativeHelper.cpp toluaNativeHelper.pkg 生成如下cpp文件。 /* ** Lua binding: toluaNavieHelper ** Generated automatically by tolua++-1.0.92 on Mon Sep 30 16:21:12 2013. */ #ifndef __cplusplus #include "stdlib.h" #endif #include "string.h" #include "tolua++.h" /* Exported function */ TOLUA_API int tolua_toluaNavieHelper_open (lua_State* tolua_S); #include "cocos2d.h" #include "NativeHelper.h" /* function to register type */ static void tolua_reg_types (lua_State* tolua_S) { tolua_usertype(tolua_S,"NativeHelper"); tolua_usertype(tolua_S,"cocos2d::CCLayer"); } /* method: openURL of class NativeHelper */ #ifndef TOLUA_DISABLE_tolua_toluaNavieHelper_NativeHelper_openURL00 static int tolua_toluaNavieHelper_NativeHelper_openURL00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( !tolua_isusertype(tolua_S,"NativeHelper",&tolua_err) || !tolua_iscppstring(tolua_S,2,&tolua_err) || !tolua_isboolean(tolua_S,3,&tolua_err) || !tolua_isnoobj(tolua_S,4,&tolua_err) ) goto tolua_lerror; else #endif { NativeHelper* self = (NativeHelper*) tolua_tousertype(tolua_S,0); std::string url = ((std::string) tolua_tocppstring(tolua_S,0)); bool forceCheck = ((bool) tolua_toboolean(tolua_S,false)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'openURL'",NULL); #endif { self->openURL(url,forceCheck); } } return 0; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'openURL'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE /* method: create of class NativeHelper */ #ifndef TOLUA_DISABLE_tolua_toluaNavieHelper_NativeHelper_create00 static int tolua_toluaNavieHelper_NativeHelper_create00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( !tolua_isusertable(tolua_S,&tolua_err) ) goto tolua_lerror; else #endif { { NativeHelper* tolua_ret = (NativeHelper*) NativeHelper::create(); tolua_pushusertype(tolua_S,(void*)tolua_ret,"NativeHelper"); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'create'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE /* Open function */ TOLUA_API int tolua_toluaNavieHelper_open (lua_State* tolua_S) { tolua_open(tolua_S); tolua_reg_types(tolua_S); tolua_module(tolua_S,NULL,0); tolua_beginmodule(tolua_S,NULL); tolua_cclass(tolua_S,"cocos2d::CCLayer",NULL); tolua_beginmodule(tolua_S,"NativeHelper"); tolua_function(tolua_S,"openURL",tolua_toluaNavieHelper_NativeHelper_openURL00); tolua_function(tolua_S,"create",tolua_toluaNavieHelper_NativeHelper_create00); tolua_endmodule(tolua_S); tolua_endmodule(tolua_S); return 1; } #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501 TOLUA_API int luaopen_toluaNavieHelper (lua_State* tolua_S) { return tolua_toluaNavieHelper_open(tolua_S); }; #endif 自己添加到cocos2dx工程的class目录即可。 然后在 AppDelegate.cpp 中加入 文件开始部位: extern int tolua_toluaNavieHelper_open ( lua_State * tolua_S); 调用lua环境初始化之后 CCLuaEngine * pEngine = CCLuaEngine :: defaultEngine (); CCScriptEngineManager :: sharedManager ()-> setScriptEngine (pEngine); tolua_toluaNavieHelper_open (pEngine-> getLuaStack ()-> getLuaState ()); ok; 现在你只要在lua文件中直接调用NativeHelper相关即可。如下 local nativehelper = NativeHelper:create() nativehelper:openURL("http://www.sina.com",true) 写那那么多,也不知道说清楚了没有,有问题留言吧。 有错误,也欢迎留言指点。 参考: http://blog.csdn.net/chenee543216/article/details/12172563 http://blog.csdn.net/chenee543216/article/details/12074771 http://www.himigame.com/lua-game/1259.html http://blog.csdn.net/musicvs/article/details/8166655 tolua++官网各种文档 lua官网各种文档 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |