Nowpaper 十五英寸的世界

Rich Games Developer

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

在上一篇中,使用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完成复杂的界面互动编写。

posted on 2012-09-16 23:20  nowpaper  阅读(5291)  评论(5编辑  收藏  举报