书生教你cocos2d-x-保卫萝卜(四)
这一篇博客我们做选关界面,内容没什么复杂的,之后就可以做游戏场景了。先看看效果图。
选关界面里结构如下。
一个背景一个开始按钮。然后中间部分是关卡的预览内容。鼠标(手指)拖动的时候内容画面会跟着动,松开鼠标(手指),画面会定格到相应关卡。
往左滑动是下一关,往右滑是上一关。
×××地址 http://down.51cto.com/data/1028692
创建背景以及开始按钮返回按钮什么的我就略过不提了。
重点内容有2块:
1.创建关卡预览内容。
我们一共9个关卡,每个关卡的预览内容有一个地图的预览背景,和一个塔的图标(标志着这个关卡能出现哪些塔)。
保卫萝卜把这些资源都做成图片了,包括每个关卡的预览图以及下面的塔的小图标,并没有重复利用地图里的资源。这样做是非常可怕和浪费的,不过对于我们学习来说,省了不少功夫。
我做了一个xml来记录这些信息。
<?xml version="1.0" encoding="UTF-8"?><levels count="9"><level bg="ss_map01.png" towers_icon="ss_towers_01.png"></level><level bg="ss_map02.png" towers_icon="ss_towers_02.png"></level><level bg="ss_map03.png" towers_icon="ss_towers_03.png"></level><level bg="ss_map04.png" towers_icon="ss_towers_04.png"></level><level bg="ss_map05.png" towers_icon="ss_towers_05.png"></level><level bg="ss_map06.png" towers_icon="ss_towers_06.png"></level><level bg="ss_map07.png" towers_icon="ss_towers_07.png"></level><level bg="ss_map08.png" towers_icon="ss_towers_08.png"></level><level bg="ss_map09.png" towers_icon="ss_towers_09.png"></level></levels>一共9个关卡,每个关卡有2个熟悉,预览图和小图标。不建议大家直接把这些写死在代码里,会造成难以修改。同样的我们在代码里构造了相关的类来读取这些信息。class LevelSummary:public cocos2d::CCObject{public:static LevelSummary* create(std::string bg_name,std::string towers_icon_name);virtual ~LevelSummary();private:LevelSummary();bool init(std::string bg_name,std::string towers_icon_name);CC_SYNTHESIZE_READONLY(std::string ,bg_name,BgName);CC_SYNTHESIZE_READONLY(std::string ,towers_icon_name,TowerIconName);};class LevelsSummary:public cocos2d::CCObject{public:static LevelsSummary* ShardLevelsSummary();virtual ~LevelsSummary();bool init();LevelSummary* GetLevel(int index);private:LevelsSummary();CC_SYNTHESIZE_READONLY(int ,level_count,LevelCount);cocos2d::CCArray* levels_array;};由于我们现在只记录了关卡预览所需要的信息,因此我称这个类为levelSummary,如果之后把每关的出兵序列也加进来,就变成levelbase了。每个levelSummary 有2个熟悉CC_SYNTHESIZE_READONLY(std::string ,bg_name,BgName);
CC_SYNTHESIZE_READONLY(std::string ,towers_icon_name,TowerIconName);预览的背景图的名字,和图标的名字。
而存储和管理它们的类为LevelsSummary(这里容易混淆,只多了个S,如果改成LevelsManager更合理)。
这是一个单例。他给我们提供了一个接口GetLevel让我们能拿到每一关的信息。
bool LevelsSummary::init(){tinyxml2::XMLDocument* doc=new tinyxml2::XMLDocument();doc->LoadFile("levels_summary.xml");tinyxml2::XMLElement *root_node=doc->RootElement();std::string count_str= root_node->Attribute("count");this->level_count=cocos2d::CCString::create(count_str)->intValue();tinyxml2::XMLElement *level_node=root_node->FirstChildElement("level");levels_array=cocos2d::CCArray::create();levels_array->retain();while (level_node){std::string bg=level_node->Attribute("bg");std::string towers_icon=level_node->Attribute("towers_icon");LevelSummary* ls=LevelSummary::create(bg,towers_icon);levels_array->addObject(ls);level_node=level_node->NextSiblingElement();}delete doc;returntrue;}在创建这个类的时候,会读取xml里的内容,把每关的信息读进内存里。
下面看选关界面内如何根据这个类创建我们要显示的内容。
levels_node=cocos2d::CCNode::create();this->addChild(levels_node);levels_node->setPosition(ccp(0,0));cocos2d::CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("stages_theme1.plist");int start_btn_y=0;for(int i=0;i<level_count;i++){std::string temp_map_name=level_summary->GetLevel(i)->getBgName();std::string temp_icon_name=level_summary->GetLevel(i)->getTowerIconName();cocos2d::CCSprite* level_map_bac=cocos2d::CCSprite::createWithSpriteFrameName(temp_map_name.c_str());levels_node->addChild(level_map_bac);level_map_bac->setPosition(ccp(win_size.width/2+i*win_size.width,win_size.height/2));cocos2d::CCSprite* level_towers_icon=cocos2d::CCSprite::createWithSpriteFrameName(temp_icon_name.c_str());levels_node->addChild(level_towers_icon);level_towers_icon->setPosition(ccp(win_size.width/2+i*win_size.width,win_size.height/2-level_map_bac->getContentSize().height/2-level_towers_icon->getContentSize().height/2));if(start_btn_y==0){start_btn_y=(level_towers_icon->getPositionY()-level_towers_icon->getContentSize().height/2)/2;}}中间的部分是可以滑动的,所以我们单开了一个节点levels_node来存储这些内容。当手指滑动屏幕时,这个节点会跟着偏移。
节点默认初始位置是屏幕左下角。之后遍历所有的关卡。创建出关卡背景预览图和小图标。
第一个关卡的背景图是在屏幕正中央,而之后的关卡预览图每个向右偏移半个屏幕大小。
诺,效果如图。
读取并创建完这些信息后,我们实现手指滑动改变当前关卡的操作。
void SelectLevelLayer::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent){cocos2d::CCTouch* touch=dynamic_cast<cocos2d::CCTouch*> (pTouches->anyObject());start_drag_point=touch->getLocation();start_drag_level_node_point=levels_node->getPosition();}当我们手指按下时,记录此时手指的坐标start_drag_point,以及此时levels_node的坐标start_drag_level_node_point
void SelectLevelLayer::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent){ cocos2d::CCTouch* touch=dynamic_cast<cocos2d::CCTouch*> (pTouches->anyObject());float px=touch->getLocation().x-start_drag_point.x;float py=0;float new_node_point_x=start_drag_level_node_point.x+px;float new_node_point_y=start_drag_level_node_point.y+py; levels_node->setPosition(ccp(new_node_point_x,new_node_point_y)); }
在手指滑动时,取得此时手指的坐标,算出偏移值
然后利用偏移值px和刚才记录的关卡节点的坐标start_drag_level_node_point,算出新的坐标,赋给节点,就可以实现关卡跟着手指移动的效果了。
void SelectLevelLayer::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent){cocos2d::CCTouch* touch=dynamic_cast<cocos2d::CCTouch*> (pTouches->anyObject());int new_level_index= this->select_level_index;float px=touch->getLocation().x-start_drag_point.x;if(px>200){//右移 上一关new_level_index=this->select_level_index-1;if(new_level_index<0){new_level_index=0;}}elseif(px<-200){//左移,下一关new_level_index=this->select_level_index+1;if(new_level_index> LevelsSummary::ShardLevelsSummary()->getLevelCount()-1){new_level_index=LevelsSummary::ShardLevelsSummary()->getLevelCount()-1;}}this->ChangeSelectLevel(new_level_index);}
最后,当手指抬起时,我们用此时的坐标和刚才按下时记录的坐标进行比较。看看到底用户是想切换到下一关还是上一关。
右移是上一关,左移是下一关,同时我们设置如果移动的偏移没有超过200像素则该操作无效。并且我们对关卡进行了保护,不能切换到-1或是大于关卡总数的关卡索引。
最后根据我们得到的关卡索引new_level_index校准关卡节点的坐标。本例中它的范围是0-8,因为我们之后9关。
ChangeSelectLevel(int index)函数是根据最后得到的关卡索引校准关卡节点的坐标,因为我们不能让关卡节点保持上图那种样子,最后比如让玩家选中的关卡的预览信息处于屏幕正中。
void SelectLevelLayer::ChangeSelectLevel(int new_level_index){
cocos2d::CCSize win_size=cocos2d::CCDirector::sharedDirector()->getWinSize();
select_level_index=new_level_index;
levels_node->setPositionX(-1*select_level_index*win_size.width);
}
当选中第0关时,节点x坐标是0。每增加一个关卡,则节点整体左移一个屏幕的偏移,使得对应关卡预览图在屏幕中央。
效果如图。同时我们记录了这个关卡的索引,知道当前选的是第几关。
选关界面到底结束。点击开始按钮后,我们更具当前选的关卡id,去找到关卡信息(可能我将这些内容添加到levelsummary里,也可能单独开个类)。然后根据关卡的具体信息创建场景,切换过去。
游戏场景里的内容我尽快更新。
除去界面,场景里的东西无非下面这些,大家可以先思考一下如何实现:
1,萝卜,10点血
2,怪物,出现后,按路径向萝卜移动
3,防御塔,会***范围内的怪物
4,障碍物,阻挡我们建塔,打掉后有奖励,并且可以空出空间造塔
5,地图
6,×××
由于部分×××有减速效果,我们可能还要写个buff类。
今天就更新到这里,大家下次见
转载于:https://blog.51cto.com/luoposhusheng/1334242
本文介绍使用Cocos2d-x创建游戏选关界面的过程,涵盖背景及按钮设计、关卡预览内容生成及滑动切换关卡等功能实现。

![p_w_picpath_thumb[1] p_w_picpath_thumb[1]](https://i-blog.csdnimg.cn/blog_migrate/50f081a9cd33b940d1fa5549dbc81a50.png)
![p_w_picpath_thumb[2] p_w_picpath_thumb[2]](https://i-blog.csdnimg.cn/blog_migrate/1ce824ff02e2464a4068af1eff242637.png)
![p_w_picpath_thumb[3] p_w_picpath_thumb[3]](https://i-blog.csdnimg.cn/blog_migrate/5f90dc5950db5f5f45e3a19f3a37c374.png)
![p_w_picpath_thumb[4] p_w_picpath_thumb[4]](https://i-blog.csdnimg.cn/blog_migrate/dc030ce5e6ed4b1643160d62b11fbb6b.png)
![p_w_picpath_thumb[5] p_w_picpath_thumb[5]](https://i-blog.csdnimg.cn/blog_migrate/2a91f0f73e7d13bc5ca6c1db8e86e15b.png)
422

被折叠的 条评论
为什么被折叠?



