書生教你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關。
ChangeSelectLevelint 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類。
今天就更新到這裡,大家下次見
本文出自 “書生教你cocos2dx” 博客,請務必保留此出處http://luoposhusheng.blog.51cto.com/8148702/1334242