• cocos2dx lua binding ,cocos2dx 绑定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:@"
    
    "
                                       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,1,"NativeHelper",0,&tolua_err) ||
         !tolua_iscppstring(tolua_S,2,0,&tolua_err) ||
         !tolua_isboolean(tolua_S,3,1,&tolua_err) ||
         !tolua_isnoobj(tolua_S,4,&tolua_err)
     )
      goto tolua_lerror;
     else
    #endif
     {
      NativeHelper* self = (NativeHelper*)  tolua_tousertype(tolua_S,1,0);
      std::string url = ((std::string)  tolua_tocppstring(tolua_S,2,0));
      bool forceCheck = ((bool)  tolua_toboolean(tolua_S,3,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,1,"NativeHelper",0,&tolua_err) ||
         !tolua_isnoobj(tolua_S,2,&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,"NativeHelper","NativeHelper","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官网各种文档

  • 相关阅读:
    自定义CopyOnWriteHashMap
    NIO中Buffer缓冲区的实现
    TOMCAT原理详解及请求过程
    XSS的原理分析与解剖
    mysql分页查询优化
    java如何正确停止一个线程
    Centos搭建ElasticSearch
    redis集群原理
    Idea-每次修改JS文件都需要重启Idea才能生效解决方法
    java 加密 解密 Illegal key size
  • 原文地址:https://www.cnblogs.com/riskyer/p/3348105.html
Copyright © 2020-2023  润新知