不知道有多少朋友了解动画和电影的制作手法,他们都是一个场景一个场景的拍摄录制,然后剪辑成为一部完整的片子,而游戏是非常类似,你可以理解要制作一个世界,然后让玩家其中按照世界的规则进展,而屏幕就是最好的观察者,可是好的片子要有一个“指挥”世界运转,让主角按照预定的路线行进,这在cocos2d中对应的是导演类(CCDirector),在http://www.cnblogs.com/hielvis/archive/2012/06/05/2534706.html中诠释的非常清晰,如想深入建议好好读读。
现在拿出之前的设计材料,好好想想游戏该有什么场景,在本篇游戏中,将会主要在如下的四个场景切换:
从上图中可以看出是开始,然后到选择战役,再到游戏中,最后为结束,游戏的主体的流程就这么搞定。
开始 第一个场景 |
之前的代码只是进了一个Test场景,现在咱们做一个新的场景,先将上面的开始界面完成,把图片的素材准备好,将界面拆分主要有背景图、按钮、标志,将图片保存兵添加到Content里:
下面打开Scenes里的SceneStart.cs,把类写成下面这样:
public class SceneStart : CCScene { public SceneStart() { base.init(); //取得屏幕大小 CCSize size = CCDirector.sharedDirector().getWinSize(); //背景图 CCSprite background = CCSprite.spriteWithFile("bg_start") ; this.addChild(background); //Logo图 CCSprite logo = CCSprite.spriteWithFile("logo"); //设置到界面中间偏上 logo.position = new CCPoint(size.width / 2, size.height / 2 + 120); this.addChild(logo); //两个按钮 CCMenuItemImage btn_start = CCMenuItemImage.itemFromNormalImage("btn_start1", "btn_start2", this, click_start); CCMenuItemImage btn_setting = CCMenuItemImage.itemFromNormalImage("btn_setting1", "btn_setting2", this, click_setting); //MenuItem需要通过CCMenu组合 CCMenu menu = CCMenu.menuWithItems(btn_start, btn_setting); //一个垂直间隔排列 menu.alignItemsVerticallyWithPadding(10); //设置到界面中间偏下 menu.position = new CCPoint(size.width / 2, size.height / 2 - 120); this.addChild(menu); } private void click_start(CCObject sender) { } private void click_setting(CCObject sender) { } }
初步写完之后可能会需要引用using cocos2d;然后在AppDelegate.cs里面做如下修改:
public class AppDelegate : CCApplication { public AppDelegate(Game game, GraphicsDeviceManager graphics) : base(game, graphics) { CCApplication.sm_pSharedApplication = this; } public override bool applicationDidFinishLaunching() { //初始化CCDirector CCDirector pDirector = CCDirector.sharedDirector(); pDirector.setOpenGLView(); //是否显示FPS(每秒帧速率) pDirector.DisplayFPS = true;
// 在这里设置Updata的间隔 pDirector.animationInterval = 1.0 / 60; // 创建一个场景 CCScene pScene = new Scenes.SceneStart(); // 运行这个场景 pDirector.runWithScene(pScene); return true; } }
你会发现:CCScene pScene = new Scenes.SceneStart();之后通过pDirector.runWithScene(pScene)进入了这个场景,pDirector就是导演,他说:现在要拍摄开始界面的场景了。
当然里面有很多的布景道具什么的,在上面的代码中就已经完成,现在运行一下看看:
奇怪,这是为什么会变成这样呢,这里说一下CCSprite,CCSprite一般叫精灵类,它的主要作用是呈现图片,在cocos2dxna中没有专门Image类,一切的图片就是通过CCSprite来显示和操作的,CCSprite载入图片后按照(0.5,0.5)的中心点(也叫锚点anchorPoint)为准,也就是说所在的xy的位置实际为其承载图片的中心位置,所以我们需要做一下坐标修改或者将锚点设置到(0,0)的位置上。比如说:
anchorPoint = new CCPoint(0, 0);
下面简单说一下代码,cocos2dxna的坐标周是在屏幕的左下,这一点和cocos2d其他版本是一致的,主要是为了统一标准,当然这也带来了理解上的麻烦,当然了,万能的导演(CCDirector)也提供了转换方法,但是我们在这里不需要太多,为了统一性,建议就按照左下的坐标开发比较好。
CCSprite的CCSprite.spriteWithFile静态方法可以很方便的将我们所需图片生成,不必自己在写很多的代码了,只需要一行,spriteWithFile所取得是对应在Content资源工程里的图片文件,CCSprite也可以控制其坐标位置,开始场景中,就用了position来控制位置,将Logo固定到了中间偏上的位置。
按钮类CCMenu单独是没有作用的,需要通过多个子项目来初始化自己,所以就有了两个菜单的代码,CCMenuItemImage也有静态方法帮助开发者写很少的代码完成按钮,CCMenuItemImage是CCMenuItem的派生类,由CCMenuItem派生的还有CCMenuItemLabel、CCMenuItemSprite等,它们的作用跟名字一样,只是看如何方便使用了。
去掉FPS |
这个时候会说左下角的帧数显示实在太难受了,能不能去掉,当然可以,直接把导演的DisplayFPS设置成为false就可以,但是cocos2dxna有个bug,去掉之后运行是下面这个样子的:
这个bug的解决方法,也很简单,就是在AppDelegate里初始化一下Font就行了,这是因为内部的处理机制造成的。
CCLabelTTF a = CCLabelTTF.labelWithString("0", "Arial", 0);
加入上面的代码就可以,不用添加进去,现在运行看看:
是不是帅多了?也许现在迫不及待的赶紧弄下一个场景,先打住,现在聊聊更加重要的话题:
庞大的资源 纹理图片优化 plist |
现在打开你的工程目录找到bin下面所编译的程序,看看Content里(Content是输出工程的内容集合,你所见的都将会打包到XAP中)输出的XNB文件吧:
现在,你能忍吗?其实原图不打包才400多KB,为什么转换之后就变成这么夸张了呢,因为XNA对资源内容都会自行编译输出,这是为了方便自己,同时将不规格的资源内容编译成规格的,这方面如果说多了就会涉及到图像渲染的细节,这么说吧,对于图像渲染显示而言,它们其实只认2的N次幂长宽的图像,无论是程序还是硬件,它的输入和输出都遵循这个规则,所以,你的精美小图片不管用什么存储最终都会变成统一规格。
一种方法是通过图像纹理的模式修正,将其变成2的N次幂长宽的图像,请看下图:
你的所有的图像都会默认为color格式,所以很悲催的事实就是将面临超大的图像素材体积(内部还给你扩展成了2的N次幂),DxtCompressed格式则可以大大的减小图像体积,但是DxtCompressed对图像有一定的要求,最基本的要求是:2的N次幂宽高
对于图像资源,很难有正好的符合,刻意的制作就会代码N多代码的修正,我们利用cocos2d的特性来解决,在cocos2d有一种将很多图片保存成为一张大图片,然后独取出来单独使用,这个方法就是plist的图片帧文件,它能极大的减小图片体积,最重要的是大图就能符合2的N次幂宽高的要求了。
TexturePackerGUI是专门制作cocos2d plist文件的软件,这个软件最好的优势是有Windows版本的(有很多优秀的工具都在IOS运行),下面是简单的使用方法:
先打开TexturePackerGUI,将前面的开始界面素材拖入到窗口中。
建议将DataFormat改成cocos2d-0.99.4,然后点击Publish按钮,保存为GameUI01.plist,浏览位置就会发现多出一个GameUI01.png,它们之间就是对应的,现在我们在程序里使用它们,将其添加到Content工程里,然后做如下两个修改:
1、修改一下GameUI01.png的Content Processor内Textrue Format属性为DxtCompressed。
2、修改GameUI01.plist的输入和输出管线,因为plist需要cocos2dxna的独特的内容管线,所以先添加引用:
然后选择GameUI.plist属性,将输入和输出的管线修改:
现在编译一下看看,呵呵,你会发现一个错,这个错是关于重复名称的,所以你需要将生成的plist文件和png文件分开,比如说建立一个images目录,推荐在plist所在的文件目录下建立Images目录将对应的png加入,因为在代码中会自动处理并寻找对应的图像文件,好了,现在再来一次编译吧。
现在再看GameUI01所生成的两个xna文件,两个加起来只有1MB,已经大大的减少了体积,在png图像里还有很多的空位,也许完全能够留给其他的UI界面。
如何使用plist |
下一步就是如何在代码中使用plist文件,打开SceneStart.cs代码我们做一下改造。
public class SceneStart : CCScene { public SceneStart() { base.init(); CCSpriteFrameCache.sharedSpriteFrameCache().addSpriteFramesWithFile("GameUI01", "images/GameUI01"); //取得屏幕大小 CCSize size = CCDirector.sharedDirector().getWinSize(); //背景图 CCSprite background = CCSprite.spriteWithSpriteFrameName("bg_start.png") ; background.anchorPoint = new CCPoint(0, 0); this.addChild(background); //Logo图 CCSprite logo = CCSprite.spriteWithSpriteFrameName("logo.png"); //设置到界面中间偏上 logo.position = new CCPoint(size.width / 2, size.height / 2 + 120); this.addChild(logo); //两个按钮 CCMenuItemSprite btn_start = CCMenuItemSprite.itemFromNormalSprite( CCSprite.spriteWithSpriteFrameName("btn_start1.png"), CCSprite.spriteWithSpriteFrameName("btn_start2.png"), this, click_start); CCMenuItemSprite btn_setting = CCMenuItemSprite.itemFromNormalSprite( CCSprite.spriteWithSpriteFrameName("btn_setting1.png"), CCSprite.spriteWithSpriteFrameName("btn_setting2.png"), this, click_start); //MenuItem需要通过CCMenu组合 CCMenu menu = CCMenu.menuWithItems(btn_start, btn_setting); //一个垂直间隔排列 menu.alignItemsVerticallyWithPadding(10); //设置到界面中间偏下 menu.position = new CCPoint(size.width / 2, size.height / 2 - 120); this.addChild(menu); } private void click_start(CCObject sender) { } private void click_setting(CCObject sender) { } }
这段代码中使用CCSpriteFrameCache载入了plist文件和png文件,用它们来提前所需要的图片帧,之后在程序中使用,CCSpriteFrameCache是一个仓库,使用文件名来标识所有的内容资源,CCSprite.spriteWithSpriteFrameName能够直接依据文件名从中取出使用,关于CCSpriteFrameCache将应用在动画等图像处理方面,这次仅仅是一个简单的图片应用示例。
本次代码仍然在:https://github.com/Nowpaper/SanguoCommander_cocos2dxna_Sample
关于TexturePackerGUI软件,可以在网上搜索到使用。
本想在本次写完切换的,看了看内容已经够多了,还是下一篇完成吧:)