Cocos2d-xna : 橫版戰略游戲開發實驗3 Scene和Director場景切換


在上一篇中,使用CCSprite和CCMenu構建了開始場景,並且說明了關於優化程序內容的問題,一個好的游戲會有很多的場景場景組合,每個場景管理自身的腳本也就是規則,在整個游戲中是如何跳轉場景的呢?先看下圖:

本圖來自Elvis的CCDirector類解析配圖,先不用看太全面,只需要看最上面的就行了,前面說過,整個游戲有一個導演(CCDirector)在管理整個場景,為了讓切換場景完成的更好,需要按照之前的場景制作方法將其他的場景補齊,即例如關卡選擇界面、游戲界面、游戲結束界面的完成。

完成全部的場景

在制作前需要生成圖片資源

QQ截圖20120916221030

上面的資源中,包含了基本場景的元素,和一張用來演示游戲界面的示意圖,打開TexturePackerGUI,將它們組合,由於有幾張比較大的圖,制作的時候看看是否有浪費,也可以將它們分成多個plist,比如說,我這次將一定會用上的圖片打包到GameUI01.plist,而預覽圖就打包到了GameUI02.plist中,將它們添加到Content里:

image

好了,現在有了兩個資源plist,GameUI01在SceneStart類中載入過,為了保證資源載入的統一性,建立一個GameRoot的類,並用靜態的方法取得,不要忘記將SceneStart里的addSpriteFramesWithFile刪除:

public class GameRoot
{
    public static void InitializeResource()
    {
        CCSpriteFrameCache.sharedSpriteFrameCache().addSpriteFramesWithFile("GameUI01", "images/GameUI01");
        CCSpriteFrameCache.sharedSpriteFrameCache().addSpriteFramesWithFile("GameUI02", "images/GameUI02");
    }
}

注意要把GameRoot.InitializeResource();添加到AppDelegate.cs的applicationDidFinishLaunching函數中,注意要添加到場景跳轉的前面一行,這樣場景在構建的時候就會先載入了圖片資源。

也許有更好的方案,比如放在一個Loading界面里面,在這里GameRoot還有其他的作用,就如它的名字當成游戲根來處理,我們可以在這里將所有的場景集合管理,采用單例的方式完成全局的控制訪問,我們可以這樣做:

//通過一個全局的根來管理整個游戲的所有場景實例
public class GameRoot
{
    public static void InitializeResource()
    {
        CCSpriteFrameCache.sharedSpriteFrameCache().addSpriteFramesWithFile("GameUI01", "images/GameUI01");
        CCSpriteFrameCache.sharedSpriteFrameCache().addSpriteFramesWithFile("GameUI02", "images/GameUI02");
    }
        
    private static SceneStart _SceneStart;
    public static SceneStart pSceneStart
    {
        get
        {
            if (_SceneStart == null)
                _SceneStart = new SceneStart();
            return _SceneStart;
        }
    }

    private static SceneSelect _SceneSelect;
    public static SceneSelect pSceneSelect
    {
        get
        {
            if (_SceneSelect == null)
                _SceneSelect = new SceneSelect();
            return _SceneSelect;
        }
    }
    private static SceneGame _SceneGame;
    public static SceneGame pSceneGame
    {
        get
        {
            if (_SceneGame == null)
                _SceneGame = new SceneGame();
            return _SceneGame;
        }
    }
    private static SceneOver _SceneOver;
    public static SceneOver pSceneOver
    {
        get
        {
            if (_SceneOver == null)
                _SceneOver = new SceneOver();
            return _SceneOver;
        }
    }
}

由於比較長,給折疊了,在這里可以保證唯一的單例完成統一管理,在游戲的任何地方,都可以呼喚GameRoot取得場景實例了。

下面是SceneSelect類的代碼,選擇界面如果想做的復雜的話就得這么搞了,當然這樣也更有趣,本篇該類代碼只是實現了基本功能,未來在用到CCAction類的時候將它做到更完美:

public class SceneSelect : CCScene
{
    public SceneSelect()
    {
        base.init();
        //背景圖
        CCSprite background = CCSprite.spriteWithSpriteFrameName("bg_select.png");
        background.anchorPoint = new CCPoint(0, 0);
        this.addChild(background);

        CCMenuItemSprite btn_back = CCMenuItemSprite.itemFromNormalSprite(
            CCSprite.spriteWithSpriteFrameName("btn_back1.png"),
            CCSprite.spriteWithSpriteFrameName("btn_back2.png"),
            this, click_back);
        CCMenu menu = CCMenu.menuWithItems(btn_back);
        menu.position = new CCPoint(666,32);
        this.addChild(menu);

        CCSprite tab1 = CCSprite.spriteWithSpriteFrameName("tab_shu1.png");
        CCSprite tab2 = CCSprite.spriteWithSpriteFrameName("tab_wu2.png");
        CCSprite tab3 = CCSprite.spriteWithSpriteFrameName("tab_wei2.png");
        tab1.position = new CCPoint(115, 430);
        tab2.position = new CCPoint(335, 430);
        tab3.position = new CCPoint(575, 430);
        this.addChild(tab1);
        this.addChild(tab2);
        this.addChild(tab3);

        CCPoint offset = new CCPoint(150, 150);
        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);
                menu = CCMenu.menuWithItems(level);
                menu.position = new CCPoint(offset.x + 160 * i,offset.y + 85 * j);
                this.addChild(menu);
            }
        }
    }
    private void click_back(CCObject s)
    {
    }
    private void click_level(CCObject sender)
    {
    }
}

場景選擇的實現效果:

QQ截圖20120916222431

選擇關卡的場景里,全部都跳轉到SceneGame中,以后將對應的關卡進行設計。

下面是游戲場景SceneGame的代碼,這里的Code只是貼了一張圖,然后加了一個“出征”按鈕,這個出征按鈕在本例中將做成游戲結束的觸發器:

public class SceneGame : CCScene
{
    public SceneGame()
    {
        base.init();
        //背景圖
        CCSprite background = CCSprite.spriteWithSpriteFrameName("bg_game.png");
        background.anchorPoint = new CCPoint(0, 0);
        this.addChild(background);
        //返回按鈕
        CCMenuItemSprite btn_attack = CCMenuItemSprite.itemFromNormalSprite(
            CCSprite.spriteWithSpriteFrameName("btn_soldierattack1.png"),
            CCSprite.spriteWithSpriteFrameName("btn_soldierattack2.png"),
            this, click_attack);
        CCMenu menu = CCMenu.menuWithItems(btn_attack);
        menu.position = new CCPoint(732, 36);
        this.addChild(menu);
    }
    private void click_attack(CCObject sender)
    {}
}

代碼效果如下:

QQ截圖20120916222716

最后一個是結束場景:

public class SceneOver : CCScene
{
    public SceneOver()
    {
        base.init();
        //背景圖
        CCSprite background = CCSprite.spriteWithSpriteFrameName("bg_over.png");
        background.anchorPoint = new CCPoint(0, 0);
        this.addChild(background);
        //文字
        CCSprite title = CCSprite.spriteWithSpriteFrameName("text_over.png");
        title.position = new CCPoint(CCDirector.sharedDirector().getWinSize().width / 2, CCDirector.sharedDirector().getWinSize().height / 2 + 150);
        this.addChild(title);
        //返回按鈕
        CCMenuItemSprite btn_back = CCMenuItemSprite.itemFromNormalSprite(
            CCSprite.spriteWithSpriteFrameName("btn_back1.png"),
            CCSprite.spriteWithSpriteFrameName("btn_back2.png"),
            this, click_back);
        CCMenu menu = CCMenu.menuWithItems(btn_back);
        menu.position = new CCPoint(666, 32);
        this.addChild(menu);
    }
    private void click_back(CCObject s)
    {}
}

效果如下:

QQ截圖20120916222936

 

場景切換 Transition

好了, 我們現在完成了基本的場景,現在要進行場景的切換操作,下面將會用上三個CCDirector類方法:

popScene() : 返回到上一個場景

pushScene(CCScene pScene) :切換到一個指定的場景

replaceScene(CCScene pScene) :替換掉當前的場景

在CCDirector中場景管理是一個隊列,寫說明還是比較麻煩,下面畫張圖來表示一下:

QQ截圖20120916223757

如圖示意,場景隊列內部已經幫你管理好了,所以不用考慮太多。

那么在代碼中如何體現呢?只需要對對應的委托事件進行處理就行了,例如在開始界面點擊“開始”就會pushScene到SceneSelect場景,而點擊返回則執行popScene,replaceScene就很簡單了,用於在游戲結束的時將SceneGame替換成為SceneOver。

所添加的代碼如下:

SceneStart:

private void click_start(CCObject sender)
{
    CCDirector.sharedDirector().pushScene(GameRoot.pSceneSelect);
}

SceneSelect:

private void click_back(CCObject s)
{
    CCDirector.sharedDirector().popScene();
}
private void click_level(CCObject sender)
{
    CCDirector.sharedDirector().pushScene(GameRoot.pSceneGame);
}

SceneGame:

private void click_attack(CCObject sender)
{
    CCDirector.sharedDirector().replaceScene(GameRoot.pSceneOver);
}

SceneOver:

private void click_back(CCObject s)
{
    CCDirector.sharedDirector().popScene();
}

現在運行一下效果,點擊按鈕看切換。

QQ截圖20120916224716

轉場效果 Effect

最后說一說,轉場的效果,點擊直接變化是不是顯得非常的單調?更加絢麗的轉場效果在引擎中已經提供了,可以看cocos2d-xna代碼中的transition部分,幾十個切換效果任由選擇:

QQ截圖20120916224926

具體的用法非常簡單,例如我們在開始界面點擊“開始”按鈕的時候,進行一個CCTransitionFade轉場效果,這個效果可以讓屏幕一黑,然后變成新的場景,在SceneStart.cs中click_start方法里加入如下代碼:

private void click_start(CCObject sender)
{
    var s = CCTransitionFade.transitionWithDuration(0.5f, GameRoot.pSceneSelect);
    CCDirector.sharedDirector().pushScene(s);
}

這種一般情況下要折騰很久的切換效果,在引擎里只是一行代碼而已,不同的Transition有不同的參數,有興趣的朋友可以參看OpenXLive移植的cocos2d-xna里的test工程樣本,里面展示了非常多的切場效果,在這里就不再太多的演示了。

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

本篇主要講述了場景的深度制作和Transition用法,主要是對場景Scene內容,下篇中將使用CCLayer,還會結合CCAction完成復雜的界面互動編寫。


免責聲明!

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



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