程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 書生教你cocos2d-x-保衛蘿卜(四)

書生教你cocos2d-x-保衛蘿卜(四)

編輯:關於C語言

書生教你cocos2d-x-保衛蘿卜四)

這一篇博客我們做選關界面,內容沒什麼復雜的,之後就可以做游戲場景了。先看看效果圖。

image_thumb

image_thumb[1]

image_thumb[2]

選關界面裡結構如下。

一個背景一個開始按鈕。然後中間部分是關卡的預覽內容。鼠標手指)拖動的時候內容畫面會跟著動,松開鼠標手指),畫面會定格到相應關卡。

往左滑動是下一關,往右滑是上一關。

源碼下載地址 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來存儲這些內容。當手指滑動屏幕時,這個節點會跟著偏移。


節點默認初始位置是屏幕左下角。之後遍歷所有的關卡。創建出關卡背景預覽圖和小圖標。

第一個關卡的背景圖是在屏幕正中央,而之後的關卡預覽圖每個向右偏移半個屏幕大小。

image_thumb[3]

諾,效果如圖。

讀取並創建完這些信息後,我們實現手指滑動改變當前關卡的操作。

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,算出新的坐標,賦給節點,就可以實現關卡跟著手指移動的效果了。

image_thumb[4]

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。每增加一個關卡,則節點整體左移一個屏幕的偏移,使得對應關卡預覽圖在屏幕中央。


image_thumb[5]

效果如圖。同時我們記錄了這個關卡的索引,知道當前選的是第幾關。

選關界面到底結束。點擊開始按鈕後,我們更具當前選的關卡id,去找到關卡信息可能我將這些內容添加到levelsummary裡,也可能單獨開個類)。然後根據關卡的具體信息創建場景,切換過去。

游戲場景裡的內容我盡快更新。

除去界面,場景裡的東西無非下面這些,大家可以先思考一下如何實現:

1,蘿卜,10點血

2,怪物,出現後,按路徑向蘿卜移動

3,防御塔,會攻擊范圍內的怪物

4,障礙物,阻擋我們建塔,打掉後有獎勵,並且可以空出空間造塔

5,地圖

6,子彈

由於部分子彈有減速效果,我們可能還要寫個buff類。

今天就更新到這裡,大家下次見

本文出自 “書生教你cocos2dx” 博客,請務必保留此出處http://luoposhusheng.blog.51cto.com/8148702/1334242

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved