Cocos2d-x 的“HelloLua” 深入分析 (一)

我们来看一下Cocos2d-x的HelloLua示例工程。首先编译运行一下这个工程,当然,因为我在HelloWorld工程中改动了CCApplication的run函数和initInstance函数,所以这里要修改一下,与HelloWorld保持一致才能编译成功。哇!一个很COOL的农场游戏。


                      1345905857_2498.jpg



       这几乎是我见过的最令人激动的示例了。农场类游戏两年前可是非常火的!怎么做的,马上来看。


       main.h和main.cpp与HelloWorld无异。不理会了。打开AppDelegate.cpp,可以看到它与HelloWorld工程中的AppDelegate.cpp的明显不同是使用了声音引擎类SimpleAudioEngine和脚本引擎类CCScriptEngineManager。下面我们来分析一下源码。

  1. 应用程序启动时调用的函数
  2. bool AppDelegate::applicationDidFinishLaunching()
  3. {
  4.         // 初始化显示设备
  5.         CCDirector *pDirector = CCDirector::sharedDirector();
  6.         // 设置显示设备使用initInstance函数创建的OpenGL视窗
  7.     pDirector->setOpenGLView(&CCEGLView::sharedOpenGLView());
  8.         //使用高清模式
  9.     // pDirector->enableRetinaDisplay(true);

  10.         // 设置显示FPS
  11.         pDirector->setDisplayFPS(true);
  12.         //设置设备的显示方向
  13.         // pDirector->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft);
  14.         //设置FPS帧间隔时间
  15.         pDirector->setAnimationInterval(1.0 / 60);

  16.         // 通过CCLuaEngine的静态函数获取一个LUA脚本引擎实例对象指针
  17. CCScriptEngineProtocol* pEngine = CCLuaEngine::engine();
  18. // 通过CCScripEngineManager的静态函数sharedManager获取单件脚本引擎管理器的实例对象指针,并将上一句创建的LUA脚本引擎实例对象指针设为脚本引擎管理器当前进行管理的脚本引擎。
  19.     CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);

  20. #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
  21.         //在ANDROID平台下,会通过文件处理API类CCFileUtils中的getFileData取得hello.lua文件并读取到char数组中。
  22.         unsigned long size;
  23.         char *pFileContent = (char*)CCFileUtils::getFileData("hello.lua", "r", &size);

  24.         if (pFileContent)
  25.         {
  26.             //将char数组数据放入到一个新的以’\0’结尾的char数组中形成一个LUA脚本字符串
  27.             char *pCodes = new char[size + 1];
  28.             pCodes[size] = '\0';
  29.             memcpy(pCodes, pFileContent, size);
  30.             delete[] pFileContent;
  31.                 //让脚本引擎执行这个LUA脚本字符串
  32.             pEngine->executeString(pCodes);
  33.                 //释放动态申请的char数组的内存
  34.             delete []pCodes;
  35.         }
  36. #endif

  37. #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE)
  38.         //如果是Win32,IOS或MARMALADE平台,通过文件处理API类CCFileUtils中的fullPathFromRelativePath函数产生一个hello.lua在当前程序所在目录下的路径。具体实现可参看CCFileUtils_win32.cpp
  39.         string path = CCFileUtils::fullPathFromRelativePath("hello.lua");
  40.         //将这个路径的目录放入到脚本引擎的搜索目录
  41.         //path.substr会将路径中的目录取出来。
  42. pEngine->addSearchPath(path.substr(0, path.find_last_of("/")).c_str());
  43. //执行这个路径所指向的LUA文件
  44.     pEngine->executeScriptFile(path.c_str());
  45. #endif 

  46.         return true;
  47. }
复制代码

我们没有在这里面发现任何关于农场或松鼠的只言片语。我们只知道程序执行了一下“hello.lua”文件。多COOL!       我已经迫不急待的想要打开hello.lua文件一看究竟了。我们打开工程下的Resource目录,可以发现农场和松鼠的图片,还有一些声音文件,以及我们要找的lua文件,共有两个:hello.lua和hello2.lua。


1345871598_4271.JPG


点击打开hello.lua,我们来分析一下:


  1. [Cocos2d-x相关教程来源于红孩儿的游戏编程之路 CSDN博客地址:http://blog.csdn.net/honghaier] 
  2. -- 设定LUAGC的拉圾回收参数
  3. collectgarbage("setpause", 100)
  4. collectgarbage("setstepmul", 5000)
  5. --这里定义一个函数cclog,用来打印字符串参数
  6. local cclog = function(...)
  7.     print(string.format(...))
  8. end
  9. --将hello2.lua包含进来,hello2.lua定义了myadd函数的实现
  10. require "hello2"
  11. --这里调用cclog打印一个和的结果,并没什么实际用处,可略过
  12. cclog("result is " .. myadd(3, 5))

  13. ---------------
  14. --通过CCDirector:sharedDirector()来取得显示设备实例对象,并调用其getWinSize函数取得窗口大小给变量winSize
  15. local winSize = CCDirector:sharedDirector():getWinSize()

  16. -- 定义createDog函数创建松鼠
  17. local function creatDog()
  18.     --定义两个变量为每一帧图块的宽高
  19.     local frameWidth = 105
  20.     local frameHeight = 95

  21. -- 创建松鼠的动画
  22. -- 先使用CCTextureCache:sharedTextureCache()取得纹理块管理器,将dog.png放入纹理块管理器产生一张纹理返回给变量textureDog
  23. local textureDog = CCTextureCache:sharedTextureCache():addImage("dog.png")
  24. --创建一个矩形返回给变量rect 
  25. local rect = CCRectMake(0, 0, frameWidth, frameHeight)
  26. --由这个矩形从纹理上取出图块产生一个CCSpriteFrame指针返回给变量frame0
  27. local frame0 = CCSpriteFrame:frameWithTexture(textureDog, rect)
  28. --换一个新的位置的矩形返回给变量rect中
  29. rect = CCRectMake(frameWidth, 0, frameWidth, frameHeight)
  30. --由第二个矩形从纹理上取出图块产生一个CCSpriteFrame指针返回给变量frame1
  31. local frame1 = CCSpriteFrame:frameWithTexture(textureDog, rect)
  32.     --从frame0产生一个精灵返回给变量spriteDog(在C++中是CCSprite指针)
  33. local spriteDog = CCSprite:spriteWithSpriteFrame(frame0)
  34. --设置初始化时
  35. spriteDog.isPaused = false
  36. --设置精灵的位置在左上的位置
  37.     spriteDog:setPosition(0, winSize.height / 4 * 3)

  38.     --生成一个设定大小为2的CCMutableArray类的实例对象。用来存储CCSpriteFrame指针,将其指针返回给变量animFrames
  39. local animFrames = CCMutableArray_CCSpriteFrame__:new(2)
  40. --调用addObject将frame0和frame1放入animFrames
  41.     animFrames:addObject(frame0)
  42.     animFrames:addObject(frame1)
  43.     --由容器类实例对象的指针animFrames创建一个动画帧信息对象,设定每0.5秒更新一帧,返回动画帧信息对象指针给变量animation
  44. local animation = CCAnimation:animationWithFrames(animFrames, 0.5)
  45. --由animation创建出一个动画动作,将这个动画动作的指针给变量animate
  46. local animate = CCAnimate:actionWithAnimation(animation, false);
  47. --设置精灵循环运行这个动作
  48.     spriteDog:runAction(CCRepeatForever:actionWithAction(animate))

  49.     -- 每帧移动松鼠
  50. local function tick()
  51.            --如果松鼠停止动作,则返回
  52.         if spriteDog.isPaused then return end
  53.         --取得松鼠的位置
  54.         local x, y = spriteDog:getPosition()
  55.             --如果松鼠的x值已经超出屏幕宽度将x位置变为0,否则加1,这样可以实现不断的往右移动,超出后就又回到最左边
  56.         if x > winSize.width then
  57.             x = 0
  58.         else
  59.             x = x + 1
  60.         end
  61.         --重新设置松鼠位置
  62.         spriteDog:setPositionX(x)
  63.     end
  64.     --这里设置每帧调用上面的函数tick
  65.     CCScheduler:sharedScheduler():scheduleScriptFunc(tick, 0, false)
  66.     --返回松鼠精灵
  67.     return spriteDog
  68. end

  69. -- 创建农场
  70. local function createLayerFram()
  71.         --创建一个新的Layer实例对象,将指针返回给变量layerFarm
  72.     local layerFarm = CCLayer:node()

  73.     -- 由“farm.jpg”创建一个精灵实例,将指针返回给变量bg
  74.     local bg = CCSprite:spriteWithFile("farm.jpg")
  75. ---设置这个精灵实例的位置
  76. bg:setPosition(winSize.width / 2 + 80, winSize.height / 2)
  77. ----将精灵放入新创建的Layer中
  78.     layerFarm:addChild(bg)

  79.     --在农场的背景图上的相应位置创建沙地块,在i从0至3,j从0至1的双重循环中,共创建了8块沙地块。
  80.     for i = 0, 3 do
  81.         for j = 0, 1 do
  82.                    --创建沙地块的图片精灵
  83.             local spriteLand = CCSprite:spriteWithFile("land.png")
  84.                    --设置精灵的位置,在j的循环中每次向右每次增加180个位置点。在i的循环中每次会跟据i与2取模的结果向左移90个位置点,向上移95的一半数量的位置点。这样最先绘制最下面的两个沙地块,再绘制上面两个。再上面两个直至最上面两个。注意:这里的位置计算数值不必太纠结,如果是依照land.png的图片大小182x94,则这里改成spriteLand:setPosition(200 + j * 182 – (i % 2) * 182 / 2, 10 + i * 94 / 2)会更好理解一些。
  85.             spriteLand:setPosition(200 + j * 180 - i % 2 * 90, 10 + i * 95 / 2)
  86.                    --将沙地块的图片精录放入到新创建的Layer中
  87.             layerFarm:addChild(spriteLand)
  88.         end
  89.     end

  90.     -- 使用CCTextureCache:sharedTextureCache()取得纹理块管理器,将dog.png放入纹理块管理器产生一张纹理textureCrop
  91. local textureCrop = CCTextureCache:sharedTextureCache():addImage("crop.png")
  92. -- 由一个矩形从纹理取出一个图块frameCrop
  93. local frameCrop = CCSpriteFrame:frameWithTexture(textureCrop, CCRectMake(0, 0, 105, 95))
  94. -- 和刚才的沙地块一样,由图块创建出精灵并放在相应的位置上,这里不再赘述。
  95.     for i = 0, 3 do
  96.         for j = 0, 1 do
  97.             local spriteCrop = CCSprite:spriteWithSpriteFrame(frameCrop);
  98.             spriteCrop:setPosition(10 + 200 + j * 180 - i % 2 * 90, 30 + 10 + i * 95 / 2)
  99.             layerFarm:addChild(spriteCrop)
  100.         end
  101.     end

  102.     -- 调用createDog增加一个移动的松鼠精灵
  103. local spriteDog = creatDog()
  104. -- 将松鼠精录放入新创建的Layer中
  105.     layerFarm:addChild(spriteDog)

  106.     -- 定义变量touchBeginPoint,设为未使用
  107.     local touchBeginPoint = nil
  108.         --定义当按下屏幕时触发的函数
  109. local function onTouchBegan(x, y)
  110.            --打印位置信息
  111.         cclog("onTouchBegan: %0.2f, %0.2f", x, y)
  112.         --将x,y存在变量touchBeginPoint中
  113.         touchBeginPoint = {x = x, y = y}
  114.            --暂停精灵spriteDog的运动
  115.         spriteDog.isPaused = true
  116.         --返回true
  117.         return true
  118.     end
  119.         --定义当保持按下屏幕进行移动时触发的函数
  120. local function onTouchMoved(x, y)
  121.            --打印位置信息
  122.         cclog("onTouchMoved: %0.2f, %0.2f", x, y)
  123.         --如果touchBeginPoint有值
  124.         if touchBeginPoint then
  125.                    --取得layerFarm的位置,将返回结果存放在cx和cy中。
  126.             local cx, cy = layerFarm:getPosition()
  127.                    --设置layerFarm的位置受到按下移动的偏移影响
  128.             layerFarm:setPosition(cx + x - touchBeginPoint.x,
  129.                                   cy + y - touchBeginPoint.y)
  130.                    --更新当前按下位置存放到变量touchBeginPoint中
  131.             touchBeginPoint = {x = x, y = y}
  132.         end
  133.     end
  134.     --当离开按下屏幕时
  135. local function onTouchEnded(x, y)
  136.            --打印位置信息
  137.         cclog("onTouchEnded")
  138.         --将变量touchBeginPoint设为未用
  139.         touchBeginPoint = nil
  140.            --将变量spriteDog
  141.         spriteDog.isPaused = false
  142.     end
  143.     --响应按下事件处理函数
  144. local function onTouch(eventType, x, y)
  145.             --如果是按下时,调用onTouchBegan
  146.         if eventType == CCTOUCHBEGAN then
  147.             return onTouchBegan(x, y)
  148.         --如果是按下并移动时,调用onTouchMoved
  149.         elseif eventType == CCTOUCHMOVED then
  150.             return onTouchMoved(x, y)
  151.         --松开时,调用onTouchEnded
  152.         else
  153.             return onTouchEnded(x, y)
  154.         end
  155.     end
  156. --调用layerFarm的registerScriptTouchHandler函数注册按下事件的响应函数
  157. layerFarm:registerScriptTouchHandler(onTouch)
  158. --调用layerFarm的setIsTouchEnabled使layerFarm能够响应屏幕按下事件
  159.     layerFarm:setIsTouchEnabled(true)
  160.     --返回layerFarm
  161.     return layerFarm
  162. end


  163. -- 定义创建菜单层函数
  164. local function createLayerMenu()
  165.     --创建一个新Layer,将其指针返回给变量layerMenu
  166.     local layerMenu = CCLayer:node()
  167.         --定义三个本地变量
  168.     local menuPopup, menuTools, effectID
  169.     --定义本地函数menuCallbackClosePopup
  170.     local function menuCallbackClosePopup()
  171.         -- 通过参数effectID关闭指定声音
  172.         SimpleAudioEngine:sharedEngine():stopEffect(effectID)
  173.         --设置menuPopup不显示
  174.         menuPopup:setIsVisible(false)
  175.     end
  176.     --定义本地函数menuCallbackOpenPopup
  177.     local function menuCallbackOpenPopup()
  178.         -- 循环播放声音文件“effect1.wav”,并返回对应的声音ID给变量effectID
  179.         effectID = SimpleAudioEngine:sharedEngine():playEffect("effect1.wav")
  180.         -- 设置menuPopup显示
  181.         menuPopup:setIsVisible(true)
  182.     end

  183.     -- 创建图片菜单按钮,设置其两个状态(普通和按下)的图片都相同是menu2.png,返回图片菜单按钮给menuPopupItem
  184. local menuPopupItem = CCMenuItemImage:itemFromNormalImage("menu2.png", "menu2.png")
  185. -- 设置图片菜单按钮的位置在0,0点
  186. menuPopupItem:setPosition(0, 0)
  187. -- 为图片菜单按钮注册响应函数menuCallbackClosePopup
  188. menuPopupItem:registerScriptHandler(menuCallbackClosePopup)
  189. -- 由图片菜单按钮menuPopupItem创建出菜单返回给变量menuPopup
  190. menuPopup = CCMenu:menuWithItem(menuPopupItem)
  191. -- 设置菜单menuPopup的位置为屏幕中央
  192.     menuPopup:setPosition(winSize.width / 2, winSize.height / 2)
  193.     --设置menuPopup不显示。
  194. menuPopup:setIsVisible(false)
  195. --将菜单放入layerMenu中
  196.     layerMenu:addChild(menuPopup)

  197. -- 下面几行代码创建左下角的图片菜单按钮menuToolsItem及菜单menuTools,与上面的代码基本相似,不再赘述。
  198. local menuToolsItem = CCMenuItemImage:itemFromNormalImage("menu1.png", "menu1.png")
  199. menuToolsItem:setPosition(0, 0)
  200. menuToolsItem:registerScriptHandler(menuCallbackOpenPopup)
  201. menuTools = CCMenu:menuWithItem(menuToolsItem)
  202. menuTools:setPosition(30, 40)
  203.     layerMenu:addChild(menuTools)
  204.     --返回layerMenu
  205.     return layerMenu
  206. end


  207. -- 注意:以上大部分都是函数的定义,以下才是真正的游戏逻辑。我在这里加个序号方便大家读懂。
  208. -- 1。取得声音引擎的实例对象并调用其playBackgroundMusic函数加载并循环播放声音文件“background.mp3”。这里做为背景音乐
  209. SimpleAudioEngine:sharedEngine():playBackgroundMusic("background.mp3", true);
  210. -- 2。取得声音引擎的实例对象并调用其preloadEffect函数将声音文件“effect1.wav”预加载进内存。这里并不播放,预加载是为了在播放时不造成卡顿感。
  211. SimpleAudioEngine:sharedEngine():preloadEffect("effect1.wav");

  212. -- 3。创建一个场景返回给变量sceneGame
  213. local sceneGame = CCScene:node()
  214. -- 4。创建农场所用的Layer,并放入场景中
  215. sceneGame:addChild(createLayerFram())
  216. -- 5。创建菜单所用的Layer,并放入场景中
  217. sceneGame:addChild(createLayerMenu())
  218. -- 6。调用显示设备的单件实例对象的runWithScene函数运行场景sceneGame
  219. CCDirector:sharedDirector():runWithScene(sceneGame)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值