Cocos2dx 3.0 过渡篇(二十四)死不了的贪食蛇(重力版)

来源:互联网 发布:ubuntu打包system.img 编辑:程序博客网 时间:2024/05/09 11:29
近来cocos2dx的论坛刮起了一阵制作贪食蛇的潮流,我也打算来凑个热闹。不过主要目的还是因为在写3.0过渡篇的系列博客时讲的都是理论,缺少实践。这次就用贪食蛇的例子较为系统的介绍3.0与2.0的一些不同之处。(当然了,有的人肯定会说我是冲沈大海老师的书来了,这种事坚决不能忍!,我慎重说明:我的收货地址是...)
------------------
贪食蛇嘛,大家都懂的,就是那条又长又细、可伸缩自如外加弹性还OK的..蛇啦。

首先介绍下游戏制作流程:
1、游戏中有三个场景,分别是主菜单界面(HelloWorld),帮助界面(GameHelp),游戏界面(GameLayer)。
2、进入游戏场景要处理的事件有:
a、开启重力感应,在onAcceleration()回调函数里判断蛇应该往哪个方向移动;
b、用draw()方法来自定义图层显示内容,如界面中的格子,蛇头,身体,食物等;
c、通过update定时器来实时更新蛇的位置

3、请继续往下看.......

代码实现如下:
先看.h头文件:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef __HELLOWORLD_SCENE_H__  
  2. #define __HELLOWORLD_SCENE_H__  
  3.   
  4.   
  5. #include "cocos2d.h"  
  6.   
  7.   
  8. USING_NS_CC;  
  9.   
  10.   
  11. //枚举类型DIR_DEF,分别标识贪食蛇的移动方向  
  12. typedef enum {  
  13.     UP=1,  
  14.     DOWN,  
  15.     LEFT,  
  16.     RIGHT  
  17. }DIR_DEF;  
  18.   
  19.   
  20. //蛇每个节点都有自己的移动方向,因此,在节点类SnakeNode的定义中包含了行、列和方向3个成员  
  21. class SnakeNode :public cocos2d::Ref  
  22. {  
  23. public:  
  24.     int row;//行  
  25.     int col;//列  
  26.     int dir;//方向  
  27. };  
  28.   
  29.   
  30. //游戏欢迎画面,这个大家很熟的  
  31. class HelloWorld : public cocos2d::Layer  
  32. {  
  33. public:  
  34.     static cocos2d::Scene* createScene();//获取欢迎画面的Scene  
  35.     virtual bool init();    
  36.     virtual void onEnter();  
  37.     virtual void onExit();  
  38.       
  39.     CREATE_FUNC(HelloWorld);  
  40. };  
  41.   
  42.   
  43. //游戏帮助画面  
  44. class GameHelp :public cocos2d::Layer  
  45. {  
  46. public :  
  47.     virtual bool init();  
  48.     virtual void onEnter();  
  49.     virtual void onExit();  
  50.     static cocos2d::Scene * createScene();//获取帮助画面  
  51.     CREATE_FUNC(GameHelp);  
  52. };  
  53.   
  54.   
  55. //游戏画面  
  56. class GameLayer :public cocos2d::Layer  
  57. {  
  58. public :  
  59.     static cocos2d::Scene * createScene();//获取游戏画面  
  60.     virtual bool init();  
  61.     virtual void onEnter();  
  62.     virtual void onExit();  
  63.   
  64.   
  65.     virtual void draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated) override;//实现当前Layer的定义  
  66.   
  67.   
  68.     void onAcceleration(Acceleration* acc, Event* event);//重力事件的回调  
  69.       
  70.     void logic01(float t);//update的回调  
  71.       
  72.     CREATE_FUNC(GameLayer);  
  73.   
  74.   
  75. protected:  
  76.     SnakeNode *sHead;  //贪食蛇px py  
  77.     SnakeNode *sFood;  //食物  
  78.     cocos2d::Vector<Ref*> allBody;//蛇的身体,放到容器Vector中  
  79. //  cocos2d::Texture2D * chead;  
  80. };  
  81.   
  82.   
  83. #endif // __HELLOWORLD_SCENE_H__  

头文件的注释描述的还算清楚,所以大家看完后应该会对游戏的流程有了一定的概念,继续往下走。

1、创建主菜单界面的主要代码如下:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //添加项菜单进入游戏游戏、帮助、退出游戏的按钮  
  2. auto labelstart = LabelTTF::create("startGame","宋体",24);  
  3. auto labelhelp = LabelTTF::create("GameHelp","宋体",24);  
  4. auto labelexit = LabelTTF::create("exitGame","宋体",24);  
  5.   
  6. //进入游戏按钮  
  7. auto mi01 = MenuItemLabel::create(labelstart,[](Ref* sender)  
  8. {  
  9.     CCLOG("go to game");  
  10.     Director::getInstance()->replaceScene(GameLayer::createScene());//跳转到游戏场景  
  11. });  
  12. mi01->setPosition(Point(100,200));   
  13.   
  14.   
  15. //帮助按钮  
  16. auto mi02 = MenuItemLabel::create(labelhelp,[](Ref* sender)  
  17. {  
  18.     CCLOG("go to help");  
  19.     Director::getInstance()->replaceScene(GameHelp::createScene());//跳转到帮助场景  
  20. });  
  21. mi02->setPosition(Point(100,150));  
  22.   
  23.   
  24. //结束游戏  
  25. auto mi03 = MenuItemLabel::create(labelexit,[](Ref* sender)  
  26. {  
  27.     CCLOG("exit the game");  
  28.     Director::getInstance()->end();//退出游戏  
  29. });  
  30. mi03->setPosition(Point(100,50));  
  31. auto pMenu = Menu::create(mi01,mi02,mi03, NULL);  
  32. pMenu->setPosition(Point::ZERO);  
  33. this->addChild(pMenu, 1);  
2、帮助界面其实就一menu,所以我就不啰嗦介绍了,直接看下游戏界面的代码实现:
1)首先在onEnter()中打开重力感应

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void GameLayer::onEnter()  
  2. {  
  3.     Layer::onEnter();  
  4.     CCLOG("GameLayer onEnter");  
  5.   
  6.   
  7.     Device::setAccelerometerEnabled(true);//打开设备的重力感应  
  8.     auto listener = EventListenerAcceleration::create(CC_CALLBACK_2(HelloWorld::onAcceleration, this));//创建一个重力监听事件  
  9.     _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);//将listener放到事件委托中  
  10. }  
2)在init()中初始化蛇头和食物的坐标,并开启定时器实时更新蛇的坐标
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. bool GameLayer::init()  
  2. {  
  3.     if ( !Layer::init() )  
  4.     {  
  5.         return false;  
  6.     }  
  7.   
  8.   
  9.     auto labhelp = LabelTTF::create("this is game","宋体",15);  
  10.     labhelp->setPosition(Point(0,340));  
  11.     this->addChild(labhelp);  
  12.   
  13.   
  14.     auto labback = LabelTTF::create("MainMenu","宋体",15);  
  15.     auto miback = MenuItemLabel::create(labback,[](Ref* sender)  
  16.     {  
  17.         Director::getInstance()->replaceScene(HelloWorld::createScene());  
  18.     });  
  19.     miback->setPosition(Point(360,200));  
  20.   
  21.   
  22.     //chead=::CCTextureCache::sharedTextureCache()->addImage("head.png");  
  23.   
  24.   
  25.     //初始化蛇头坐标和食物的坐标,用下面这种方法随机出来的坐标每次运行时都是一样一样的......  
  26.     sHead = new SnakeNode();  
  27.     sHead->row = rand()%10;  
  28.     sHead->col = rand()%10;  
  29.   
  30.   
  31.     //初始化食物的坐标  
  32.     sFood = new SnakeNode();  
  33.     sFood->row = rand()%10;  
  34.     sFood->col = rand()%10;  
  35.   
  36.   
  37.     //执行定时任务  
  38.     this->schedule(schedule_selector(GameLayer::logic01),0.5);  
  39.     return true;  
  40. }  
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //定时器  
  2. void GameLayer::logic01(float t)  
  3. {     
  4.     //移动蛇的身体  
  5.     for(int i = allBody.size()-1; i>=0; i--)  
  6.     {   
  7.         SnakeNode * sn = (SnakeNode *)allBody.at(i);//获取蛇身体上的某个节点  
  8.           
  9.         if(i>0)   
  10.         {   
  11.             //如果该节点不是第一个节点,那么该节点的下一个坐标就是其前一个点的坐标(这里不用多解释,玩过蛇的都懂)  
  12.             SnakeNode * snpre = (SnakeNode *)allBody.at(i-1);//获取前一个节点,把前一个节点的方向,坐标传给当前节点  
  13.             sn->dir = snpre->dir;  
  14.             sn->row = snpre->row;  
  15.             sn->col = snpre->col;  
  16.         }  
  17.         else if(i==0)  
  18.         {  
  19.             //如果i=0则是第一个节点,蛇头的坐标便是该节点的坐标  
  20.             sn->dir = sHead->dir;  
  21.             sn->row = sHead->row;  
  22.             sn->col = sHead->col;  
  23.         }  
  24.     }  
  25.   
  26.   
  27.     //移动蛇头,根据dir来判断蛇头的移动方向  
  28.     switch(sHead->dir)  
  29.     {  
  30.     case DIR_DEF::UP:  
  31.         sHead->row++;//上移  
  32.         if(sHead->row >= 10)  
  33.         {  
  34.             sHead->row=0;//超过顶部边界后便从底部出来  
  35.         }  
  36.         break;  
  37.     case DIR_DEF::DOWN:  
  38.         sHead->row--;  
  39.         if(sHead->row < 0)  
  40.         {  
  41.             sHead->row=9;  
  42.         }  
  43.         break;  
  44.     case DIR_DEF::LEFT:  
  45.         sHead->col--;  
  46.         if(sHead->col < 0)  
  47.         {  
  48.             sHead->col=9;  
  49.         }  
  50.         break;  
  51.     case DIR_DEF::RIGHT:  
  52.         sHead->col++;  
  53.         if(sHead->col >= 10)  
  54.         {  
  55.             sHead->col=0;  
  56.         }  
  57.         break;  
  58.     };    
  59.   
  60.   
  61.     //碰撞检测  
  62.     //如果蛇头的横、列位置一样,说明蛇吃到了这个食物  
  63.     if(sHead->row == sFood->row && sHead->col == sFood->col)  
  64.     {   
  65.         //食物从当前位置消失,随机出现在下一个坐标  
  66.         sFood->row = rand()%10;  
  67.         sFood->col = rand()%10;  
  68.   
  69.   
  70.         //添加身体到集合  
  71.         SnakeNode * sn = new SnakeNode();//创建一个新的节点(也就是吃掉的那个食物),将其放到蛇的尾巴上  
  72.         SnakeNode * lastNode = NULL;  
  73.         //获取蛇的最后一个节点,如果allBody的size()为0,则说明蛇是第一次捕食,那么它的最后一个节点也就是蛇头啦。  
  74.         if(allBody.size()>0)  
  75.             lastNode = (SnakeNode *)allBody.back();  
  76.         else  
  77.             lastNode = sHead;//最后一个节点是蛇头  
  78.   
  79.   
  80.         //通过最后一个节点的方向来个新的节点初始化横、列坐标  
  81.         switch(lastNode->dir)  
  82.         {  
  83.         case DIR_DEF::UP:  
  84.             sn->row = lastNode->row-1;  
  85.             sn->col = lastNode->col;  
  86.             break;  
  87.         case DIR_DEF::DOWN:  
  88.             sn->row = lastNode->row+1;  
  89.             sn->col = lastNode->col;  
  90.             break;  
  91.         case DIR_DEF::LEFT:  
  92.             sn->row = lastNode->row;  
  93.             sn->col = lastNode->col+1;  
  94.             break;  
  95.         case DIR_DEF::RIGHT:  
  96.             sn->row=lastNode->row;  
  97.             sn->col=lastNode->col-1;  
  98.             break;  
  99.         }  
  100.         this->allBody.pushBack(sn);//将新的节点加入到蛇的身体中。  
  101.     }  
  102. }  
3)通过draw()绘制游戏界面的格子与食物等
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void GameLayer::draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated)  
  2. {  
  3.     ///绘制形状  
  4.     ::glLineWidth(2);//设定画线的宽度  
  5.     for(int i=0;i<11;i++)  
  6.     {  
  7.         DrawPrimitives::drawLine(Point(0,i*32),Point(320,i*32));//绘制条横线  
  8.         DrawPrimitives::drawLine(Point(i*32,0),Point(i*32,320));//绘制条竖线  
  9.     }  
  10.   
  11.   
  12.     //                    RGBA  
  13.     //DrawPrimitives::drawColor4B(ccc4(255,0,0,255));//设定画线的颜色  
  14.   
  15.   
  16.     //绘制蛇头  
  17.     DrawPrimitives::drawSolidRect(Point(sHead->col*32+2,sHead->row*32+2),  
  18.         Point(sHead->col*32+32,sHead->row*32+32),  
  19.         Color4F(Color3B(255,0,0)));  
  20.   
  21.   
  22.     //绘制食物  
  23.     DrawPrimitives::drawSolidRect(Point(sFood->col*32+2,sFood->row*32+2),  
  24.         Point(sFood->col*32+32,sFood->row*32+32),  
  25.         Color4F(Color3B(0,0,255)));  
  26.   
  27.   
  28.     //绘制身体  
  29.     for(int i=0;i<allBody.size();i++)  
  30.     {  
  31.         SnakeNode * node=(SnakeNode *)allBody.at(i);  
  32.         DrawPrimitives::drawSolidRect(Point(node->col*32+2,node->row*32+2),  
  33.         Point(node->col*32+32,node->row*32+32),  
  34.         Color4F(Color3B(0,0,255)));  
  35.     }  
  36.   
  37.   
  38.     /*Rect r(340,0,57,57); 
  39.     chead->drawInRect(r); 
  40.     Layer::draw();*/  
  41. }  
4)通过重力的回调函数来更新蛇的移动方向
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1.   
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void GameLayer::onAcceleration(Acceleration* acc, Event* event)  
  2. {  
  3.     //0.5这东西很微妙的说  
  4.     if(acc->x<=-0.5)  
  5.     {  
  6.         sHead->dir=DIR_DEF::LEFT;  
  7.         log("LEFT");  
  8.     }  
  9.     else if(acc->x>=0.5)  
  10.     {  
  11.         sHead->dir=DIR_DEF::RIGHT;  
  12.         log("RIGHT");  
  13.     }  
  14.     else if(acc->y<=-0.5)  
  15.     {  
  16.         sHead->dir=DIR_DEF::DOWN;  
  17.         log("DOWN");  
  18.     }  
  19.     else if(acc->y>=0.5)  
  20.     {  
  21.         sHead->dir = DIR_DEF::UP;  
  22.         log("UP");  
  23.     }  
  24.     else  
  25.     {  
  26.         ;  
  27.     }  
  28. }  

恩,差不都就是这样了。最后附上游戏截图,如果觉得游戏画面您还满意的话,请给我点32个赞!谢谢!~:

             

看到这里有的人可能要吐槽了,为什么没有写当蛇撞到尾巴会结束游戏的处理。原因很简单,因为我...懒...。就如开头说的那样,该篇的主要目的是通过一个例子来较为系统的介绍cocos2dx2.0与3.0一些不同的地方。

0 0