cocos2d-x 血泪史(-1) CCNotificationCenter 与LUA

lua 是个很吊的语言,为什么这么说呢,因为大家都这么说... 而且貌似是为游戏而生,在官网(http://www.lua.org/)上还有各种各样的lua 库和工具可供使用,在cocos2d-x 的scripting 目录下就可以找到cocos2d-x 提供的库文件还有一个神奇的工具tolua (使用方法见:http://blog.csdn.net/musicvs/article/details/8166572

 

等等,好像标题有点奇怪,-1 是几个意思。。 恩。。其实最近发现腾讯出了款打飞机的游戏整合了天天酷跑里面那些道具坐骑(宠物)角色各式各样的关卡和敌人当然还少不了好友攀比系统,我只能说。。太tm吊了!!!所以我的打飞机的游戏感觉没多大意思了,不过我还是会做下去的。-1 呢就是遇到的些个问题分条就在这说了,因为没那么多时间去写系列,等系列的进度碰到这些个问题的时候再引用过来好了。。。^_^

 

我的本意是游戏的主框架用cpp 写然后技能,关卡什么的用lua 写,为什么呢,我说我为了学lua 你信么。。

那么技能什么的怎么用lua 写呢,构想如下:

当释放技能(触摸到技能图标)时,主框架会使用CCNotificationCenter 的

void CCNotificationCenter::postNotification(const char *name, CCObject *object)

方法来做个广播,然后lua 里接收这个msg 做出响应,这个CCObject* 的参数可以传进去一个CCDictionary* 包含技能释放者实例,消耗的怒气值等等数据。顺便提一下在cocos2d-x 3.0 里这里参数名是CCObject* sender,大概是想说明只传入个sender 就行了或者还有其他设计方面的考虑?不明求各位看官解释。。。

然后就想写个小demo 验证下这个想法是否可行。。好吧开始行动

首先要让当前项目支持lua,去到下载的cocos2d-x 目录下把scripting 这个文件夹拷到项目里与cocos2dx,CocosDenshion 什么的同目录,然后把scripting\lua\proj.win32 里的proj 添加到solution。像这样:

当然这是不够的,右键你的项目->属性,C/C++ ->Additional Include Directories 里面加上那坨目录:

当然Linker->Input->Additional Dependencies 这里也要加上一坨东西:

注意websockets.lib 在external\libwebsockets\win32 这里由于没有见到源文件(*.cpp),所以要么把这里lib 目录加到项目的lib 目录,要么直接把external\libwebsockets\win32\lib 里的东西全拷到项目输出目录Debug.win32 下面也行。

然后build 这个liblua~ok 没问题。

接下来在项目的AppDelegate 里加上一方法:

 void AppDelegate::InitLuaEngine()
 2 {
 3     // register lua engine
 4     CCLuaEngine* pEngine = CCLuaEngine::defaultEngine();
 5     CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
 6 
 7     CCLuaStack *pStack = pEngine->getLuaStack();
 8     lua_State *tolua_s = pStack->getLuaState();
 9     tolua_extensions_ccb_open(tolua_s);
10 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)    
11     pStack = pEngine->getLuaStack();
12     tolua_s = pStack->getLuaState();
13     tolua_web_socket_open(tolua_s);
14 #endif
15         
16     std::vector<std::string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths();
17     searchPaths.push_back("script");
18     CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
19     CCLog("Lua Engine Initialized.");
20 }

当然头文件里要加上这么一段:

1 // AppDelegate.h
2 #include "CCLuaEngine.h"
3 #include "Lua_extensions_CCB.h"
4 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
5 #include "Lua_web_socket.h"
6 #endif

接下来因为我们往searchPaths 里面塞了一个"script",所以在资源目录下新建个"script" 的文件夹再在里面建个lua 文件就叫"registerNotification.lua" 好了...

然后模仿hellolua (cocos2d-x 自带的template)往里面塞上这样一些奇怪的东西:

cclog = function(...)
    print(string.format(...))
end

local LUA_TEST_MSG = "LUA TEST MSG"
local kCCNodeOnEnter = "enter"
local kCCNodeOnExit = "exit"

function __G__TRACKBACK__(msg)
    cclog("----------------------------------------")
    cclog("LUA ERROR: " .. tostring(msg) .. "\n")
    cclog(debug.traceback())
    cclog("----------------------------------------")
end

local function regNotification()
    local ccLayer = CCLayer:create();
    
    local function testNotificationHandler(obj)
        cclog("GOT MSG"  .. 1)
    end
    local function testNotificationHandler2(obj)
        cclog("GOT MSG"  .. 2)
    end
    
    local function onEnter()
        cclog("ON ENTER")
        CCNotificationCenter:sharedNotificationCenter():registerScriptObserver(ccLayer, testNotificationHandler, LUA_TEST_MSG)
        CCNotificationCenter:sharedNotificationCenter():registerScriptObserver(ccLayer, testNotificationHandler2, LUA_TEST_MSG)
    end
    
    local function onExit()
        cclog("ON EXIT")
        CCNotificationCenter:sharedNotificationCenter():unregisterScriptObserver(ccLayer, LUA_TEST_MSG)
    end
    
    local function eventHandler(eventType)
        cclog("ON EVENT: " .. eventType)
        if eventType == kCCNodeOnEnter then
            onEnter()
        elseif eventType == kCCNodeOnExit then
            onExit()
        end
    end
    
    ccLayer:registerScriptHandler(eventHandler)
    return ccLayer
end
local function regNotification2()
    local ccLayer = CCLayer:create();
    
    local function testNotificationHandler(obj)
        cclog("GOT MSG" .. 3)
    end
    local function testNotificationHandler2(obj)
        cclog("GOT MSG" .. 4)
    end
    
    local function onEnter()
        cclog("ON ENTER")
        CCNotificationCenter:sharedNotificationCenter():registerScriptObserver(ccLayer, testNotificationHandler, LUA_TEST_MSG)
        CCNotificationCenter:sharedNotificationCenter():registerScriptObserver(ccLayer, testNotificationHandler2, LUA_TEST_MSG)
    end
    
    local function onExit()
        cclog("ON EXIT")
        CCNotificationCenter:sharedNotificationCenter():unregisterScriptObserver(ccLayer, LUA_TEST_MSG)
    end
    
    local function eventHandler(eventType)
        cclog("ON EVENT: " .. eventType)
        if eventType == kCCNodeOnEnter then
            onEnter()
        elseif eventType == kCCNodeOnExit then
            onExit()
        end
    end
    
    ccLayer:registerScriptHandler(eventHandler)
    return ccLayer
end

local function main()
    cclog("LUA Main running with version: " .. _VERSION)
    local layer = regNotification()
    local layer2 = regNotification2()
    local currentScene = CCDirector:sharedDirector():getRunningScene();
    currentScene:addChild(layer)
    currentScene:addChild(layer2)
    cclog("layer added.")
end

xpcall(main, __G__TRACKBACK__)


就是往当前scene 里加上两个layer,这两个layer 都注册了两次同一个msg,然后在主程序里随便哪里放一个按钮或是menuItem,叫做button1吧,按钮回调里写上

        CCScriptEngineManager::sharedManager()->getScriptEngine()->executeScriptFile("registerNotification.lua");

另外旁边再放一个menuItem叫做button2,回调里写上

        CCNotificationCenter::sharedNotificationCenter()->postNotification("LUA TEST MSG", CCLayer::create());


啊哈,看起来不错,运行下看看吧。

先点下button2

[LUA-print] LUA Main running with version: Lua 5.1
[LUA-print] ON EVENT: enter
[LUA-print] ON ENTER
[LUA-print] ON EVENT: enterTransitionFinish
[LUA-print] ON EVENT: enter
[LUA-print] ON ENTER
[LUA-print] ON EVENT: enterTransitionFinish
[LUA-print] layer added.

然后是button1

[LUA-print] GOT MSG1
[LUA-print] GOT MSG1

MSG3 哪里去了?! 问题来了~ 对于同一个target,一个msg 只能被注册一次,对于不同的target,注册多次也只会回调第一次注册的那个方法,so~
于是我把问题抛到了cocos2d-x 的官方论坛并且附上了自己的解决方法:http://www.cocos2d-x.org/forums/11/topics/44010?r=44973#message-44973

然后laurentzubiaur 这位大神给出了不用修改cocos2d 源代码的解决方法,在lua 里把CCNotificationCenter 包上一层,哟西,太吊了!!!然后就没有然后了...

posted @ 2014-02-15 19:18  草帽过客  阅读(2094)  评论(4编辑  收藏  举报