zoukankan      html  css  js  c++  java
  • Cocos2dxna : 横版战略游戏开发实验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完成复杂的界面互动编写。

  • 相关阅读:
    搭建集群时遇到各种奇葩问题的大招~~
    oracle初学心得(转)
    "小寒"饮食养生
    时刻修正自已的思想
    myeclipse使用
    从javascript语言本身谈项目实战(转)
    Java的内存泄漏(转)
    概念解释
    小穴位大健康——李智
    历史朝代表
  • 原文地址:https://www.cnblogs.com/nowpaper/p/2688009.html
Copyright © 2011-2022 走看看