在上一篇中,使用CCSprite和CCMenu构建了开始场景,并且说明了关于优化程序内容的问题,一个好的游戏会有很多的场景场景组合,每个场景管理自身的脚本也就是规则,在整个游戏中是如何跳转场景的呢?先看下图:
本图来自Elvis的CCDirector类解析配图,先不用看太全面,只需要看最上面的就行了,前面说过,整个游戏有一个导演(CCDirector)在管理整个场景,为了让切换场景完成的更好,需要按照之前的场景制作方法将其他的场景补齐,即例如关卡选择界面、游戏界面、游戏结束界面的完成。
完成全部的场景 |
在制作前需要生成图片资源
上面的资源中,包含了基本场景的元素,和一张用来演示游戏界面的示意图,打开TexturePackerGUI,将它们组合,由于有几张比较大的图,制作的时候看看是否有浪费,也可以将它们分成多个plist,比如说,我这次将一定会用上的图片打包到GameUI01.plist,而预览图就打包到了GameUI02.plist中,将它们添加到Content里:
好了,现在有了两个资源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) { } }
场景选择的实现效果:
选择关卡的场景里,全部都跳转到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) {} }
代码效果如下:
最后一个是结束场景:
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) {} }
效果如下:
场景切换 Transition |
好了, 我们现在完成了基本的场景,现在要进行场景的切换操作,下面将会用上三个CCDirector类方法:
popScene() : 返回到上一个场景
pushScene(CCScene pScene) :切换到一个指定的场景
replaceScene(CCScene pScene) :替换掉当前的场景
在CCDirector中场景管理是一个队列,写说明还是比较麻烦,下面画张图来表示一下:
如图示意,场景队列内部已经帮你管理好了,所以不用考虑太多。
那么在代码中如何体现呢?只需要对对应的委托事件进行处理就行了,例如在开始界面点击“开始”就会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(); }
现在运行一下效果,点击按钮看切换。
转场效果 Effect |
最后说一说,转场的效果,点击直接变化是不是显得非常的单调?更加绚丽的转场效果在引擎中已经提供了,可以看cocos2d-xna代码中的transition部分,几十个切换效果任由选择:
具体的用法非常简单,例如我们在开始界面点击“开始”按钮的时候,进行一个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完成复杂的界面互动编写。