Cocos2d-xna : 橫版戰略游戲開發實驗4 Layer構建豐富的交互


本篇中主要介紹cocos2d-xna的CCLayer和CCMenu,在游戲開發中,只是使用前面提到的CCSprite和CCScene來完成豐富的交互行為是不夠的,單體的界面元素操作只會增加UI開發的復雜程度,所以像CCLayer這樣的成組操作可以為開發提供很好的便捷。這次拿關卡選擇場景做操作實驗,完成較為復雜的交互開發。

巧用CCMenuItem

拿出來咱們之前制作的資源文件,游戲設計中,將魏蜀吳三個國家分成不同的幾個關卡,這樣就要求我們在界面上需要對它們進行分開選擇,先看看圖片資源的准本情況,在GameUI01.plist里有這樣的幾個按鈕文件:

QQ截圖20120922195802

用亮紅色的按鈕表示為選定的,而暗紅色的表示可以點擊,在標簽頭上,被選定的一定是不能點擊的,所以可以巧用CCMenuItem的Enabled屬性組合達到效果,打開SceneSelect.cs類,在構造中創建Tab按鈕的地方把原有的代碼修改一下,原來的只是用CCSpirte貼了一張展示圖,詳細的可以看上一篇,

首先創建該類的一個成員:

CCMenu story_tabs;

CCMenu story_tabs一會兒就能用的上了,下面再構造函數里寫代碼如下:

//上面的Tab按鈕創建
CCMenuItemSprite tab1 = CCMenuItemSprite.itemFromNormalSprite(
    CCSprite.spriteWithSpriteFrameName("tab_shu2.png"), 
    CCSprite.spriteWithSpriteFrameName("tab_shu1.png"),
    CCSprite.spriteWithSpriteFrameName("tab_shu1.png"), 
    this, click_story_tab);
CCMenuItemSprite tab2 = CCMenuItemSprite.itemFromNormalSprite(
    CCSprite.spriteWithSpriteFrameName("tab_wu2.png"),
    CCSprite.spriteWithSpriteFrameName("tab_wu1.png"),
    CCSprite.spriteWithSpriteFrameName("tab_wu1.png"),
    this, click_story_tab);
CCMenuItemSprite tab3 = CCMenuItemSprite.itemFromNormalSprite(
    CCSprite.spriteWithSpriteFrameName("tab_wei2.png"),
    CCSprite.spriteWithSpriteFrameName("tab_wei1.png"),
    CCSprite.spriteWithSpriteFrameName("tab_wei1.png"),
    this, click_story_tab);
story_tabs = CCMenu.menuWithItems(tab1, tab2, tab3);
//按照水平方向10個像素間隔分割
story_tabs.alignItemsHorizontallyWithPadding(10);
//轉換為界面UI的坐標
story_tabs.position = CCDirector.sharedDirector().convertToUI(new CCPoint(300, 72));
//將第一個設置為不可點擊
tab1.Enabled = false;
this.addChild(story_tabs);

該代碼是創建了幾個按鈕並且組合到了一個CCMenu當中,這里需要特別說明的是,CCDirector.sharedDirector().convertToUI()方法,這個方法是將坐標轉換成為UI坐標,要知道,在cocos2d里面坐標是用左下角向上的,而不是一般的左上角,用這個方法可以方便的轉換。

現在運行不了,因為沒有實現click_story_tab方法,下面在該類中實現方法:

private void click_story_tab(CCObject sender)
{
    //遍歷story_tabs
    foreach (var item in story_tabs.children)
    {
        //判斷是否為CCMenuItem,如果是的話,排除sender以外的全部設定為true
        if(item is CCMenuItem)
            (item as CCMenuItem).Enabled = item != sender;
    }
}

也許初步看起來不太容易理解,其實這里做一下邏輯判斷就行,用if else實現就是這樣的:

if(item != sender)
    (item as CCMenuItem).Enabled = false;
else
    (item as CCMenuItem).Enabled = true;

用什么方式都行,現在運行一下看看效果

QQ截圖20120922203222

當點擊任何一個標簽的時候就會呈現激活狀態,而此時也會不能點擊,好了,下面就要考慮如何實現對應的關卡內容了。

CCLayer

上一篇的代碼中,只是用了for循環繪制了幾個按鈕然后讓按鈕觸發跳轉場景,很顯然,現在有了分類的標簽頁,下面的對應的關卡也需要改變,如果使用很粗暴的方法(每個組單獨寫按鈕,用是否可見管理)雖然能實現,但是管理起來不但麻煩,而且控制動畫也就不方便了,下面我們用CCLayer圖層來將這一大堆的按鈕放在一起,關於層的概念如果玩過PS的朋友應該很容易理解,下面這張圖當作簡要的說明:

QQ截圖20120922203223

魏蜀吳不同的標簽對應一個不同的圖層,當點擊對應時,圖層發生發生變換,所以我們抽象一個關卡的圖層類代碼如下:

public class LayerLevels : CCLayer
{
    public LayerLevels()
    {
        //關卡選擇層
        CCPoint offset = new CCPoint(170, 180);
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                //關卡的按鈕
                CCMenuItemSprite level = CCMenuItemSprite.itemFromNormalSprite(
                    CCSprite.spriteWithSpriteFrameName("btn_level1.png"),
                    CCSprite.spriteWithSpriteFrameName("btn_level2.png"),
                    this, click_level);
                CCMenu menu = CCMenu.menuWithItems(level);
                //位置相對於左上的UI界面
                menu.position = CCDirector.sharedDirector().convertToUI(new CCPoint(offset.x + 160 * i, offset.y + 85 * j));
                this.addChild(menu);
                //創建一個MenuItem,用作文本內容
                CCMenuItem menuitem = new CCMenuItem();
                //指定Arial的字體描述,保證fonts里有Arial.spritefont
                var text = CCLabelTTF.labelWithString((j * 4 + i + 1).ToString(), "Arial", 12);
                //將顏色指定為黑色
                text.Color = new ccColor3B();
                menuitem.addChild(text);
                menu.addChild(menuitem);
            }
        }
    }
    private void click_level(CCObject sender)
    {
        //當關卡點擊的時候會自動跳轉到游戲場景
        CCDirector.sharedDirector().pushScene(GameRoot.pSceneGame);
    }
    public void Show()
    {
        this.visible = true;
    }
    public void Hide()
    {
        this.visible = false;
    }
}

好了,現在回到SceneSelect.cs,將之前的按鈕for循環全部去掉,只需要一行代碼:

this.addChild(new LayerLevels());

運行看看:

QQ截圖20120922203214

有了關卡,圖層顯示,並且還有了關卡名字,其實這里你可以發揮一下,以后將來能自定義關卡名,但謹記漢字是顯示不了的,這需要另外一個漢字解決方案,以后咱們再說。

為了更好了和將來拓展,我加入了Show()和Hide()兩個方法,用來控制是否顯示,下面我們馬上就用的上啦。

但是點擊對應的魏蜀吳還不能實現切換,下面考慮如何實現頁面的切換,將標簽都對應起來,建立一個字典:

Dictionary<CCMenuItem, LayerLevels> dictLayerLevels = new Dictionary<CCMenuItem, LayerLevels>();
LayerLevels currentlayerlevers = null;

在SceneSelect構造函數中:

//添加測試層
//this.addChild(new LayerLevels());
//將標簽對應到不同的LyerLevers 類中
dictLayerLevels.Add(tab1, new LayerLevels() { visible = false });
dictLayerLevels.Add(tab2, new LayerLevels() { visible = false });
dictLayerLevels.Add(tab3, new LayerLevels() { visible = false });
//將tab1顯示為當前的關卡層
showLayerLevels(dictLayerLevels[tab1]);
//遍歷並添加到界面中
foreach (var item in dictLayerLevels.Values)
{
    this.addChild(item);
}

注意將之前的注釋掉,現在這個沒用,好了,然后實現showLayerLevels方法和在標簽點擊的事件中加入代碼,變成這個樣子:

private void click_story_tab(CCObject sender)
{
    //遍歷story_tabs
    foreach (var item in story_tabs.children)
    {
        //判斷是否為CCMenuItem,如果是的話,排除sender以外的全部設定為true
        if(item is CCMenuItem)
            (item as CCMenuItem).Enabled = item != sender;
    }
    showLayerLevels(dictLayerLevels[sender as CCMenuItem]);
}
private void showLayerLevels(LayerLevels layer)
{
    if (currentlayerlevers != null)
        currentlayerlevers.Hide();
    layer.Show();
    currentlayerlevers = layer;
}

showLayerLevels可以保證之前的關卡層隱蔽掉,將新的顯示出來。

但是現在點擊上面的標簽是沒用的,因為沒有任何的變化,只是可見和不可見,所以為了更清晰,下面將用CCAction來實現動畫效果。

CCMoveTo

CCMoveTo意思很簡單,讓一個元素從當前的位置移動到指定的新位置,它的靜態方法可以通過時間和坐標產生一個移動的CCAction,下面用它來實現圖層的移動變化,這樣當標簽切換的時候,對應的更換也就可以直接看得到。那么打開LayerLevels類,把Show方法做一下修改:

public void Show()
{
    //將其顯示出來
    this.visible = true;
    //把位置設置到最右邊出屏幕外
    this.position = new CCPoint(CCDirector.sharedDirector().getWinSize().width,0);
    //指定移動到0,0點
    CCMoveTo move = CCMoveTo.actionWithDuration(0.5f,new CCPoint(0,0));
    //運行這個Action
    this.runAction(move);
}

好了,運行一下,看到了滑動效果了嗎?這個效果,當然了,這個效果還不能通過手勢來控制,只能點擊上面的魏蜀吳。

更進一步,我們現在看這個效果還是有點別扭,就是之前頁面是直接消失掉的,能不能跟滑動滾動走呢,這里就需要另外一個行為CCSequence隊列行為來實現,隊列行為在之前的一篇中有詳細的說明:

Cocos2d-x for WindowsPhone:開發一個打地鼠游戲(下)

我們將用上這個Action來實現Hide方法,當隱蔽動畫完成之后將本圖層隱蔽,改造Hide方法並添加回調方法:

public void Hide()
{
    //指定移動到最左邊並超出屏幕
    CCMoveTo move = CCMoveTo.actionWithDuration(0.5f,new CCPoint(-CCDirector.sharedDirector().getWinSize().width,0));
    //執行一個隊列行為,當移動完成后就會調用HideAniCompled
    this.runAction(CCSequence.actionOneTwo(move, CCCallFunc.actionWithTarget(this, HideAniCompled)));
}
void HideAniCompled()
{
    this.visible = false;
}

現在再運行一下:

QQ截圖20120922203224

當點擊對應的標簽時候就會發生變化,交互是否立即豐富了很多呢?現在你可以嘗試自己做一些行為效果發揮想象力。

本篇主要對CCLayer和CCAction結合應用達到關卡選擇場景的交互開發,沒有做太多的其他考慮,在正式開發中,關卡選擇界面和關卡設計緊密相關,對應數據的構建和設計至關重要,該部分在后面我們一步一步的完成它。

關於Action有很多的方法,有興趣的朋友可以參看OpenXLive移植的cocos2d-xna里的test工程樣本,里面展示了非常多的行為效果,例如放縮、切變、不透明等等,在這里就不再太多的講解。

本篇例子工程:https://github.com/Nowpaper/SanguoCommander_cocos2dxna_Sample
本例工程名為:SanguoCommander4


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM