• Cocos2dxna : 横版战略游戏开发实验2 Sprite和Scene场景制作


    不知道有多少朋友了解动画和电影的制作手法,他们都是一个场景一个场景的拍摄录制,然后剪辑成为一部完整的片子,而游戏是非常类似,你可以理解要制作一个世界,然后让玩家其中按照世界的规则进展,而屏幕就是最好的观察者,可是好的片子要有一个“指挥”世界运转,让主角按照预定的路线行进,这在cocos2d中对应的是导演类(CCDirector),在http://www.cnblogs.com/hielvis/archive/2012/06/05/2534706.html中诠释的非常清晰,如想深入建议好好读读。

    现在拿出之前的设计材料,好好想想游戏该有什么场景,在本篇游戏中,将会主要在如下的四个场景切换:

    st010101

    从上图中可以看出是开始,然后到选择战役,再到游戏中,最后为结束,游戏的主体的流程就这么搞定。

      开始 第一个场景

    之前的代码只是进了一个Test场景,现在咱们做一个新的场景,先将上面的开始界面完成,把图片的素材准备好,将界面拆分主要有背景图、按钮、标志,将图片保存兵添加到Content里:

    QQ截图20120912092832

    下面打开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就是导演,他说:现在要拍摄开始界面的场景了。

    当然里面有很多的布景道具什么的,在上面的代码中就已经完成,现在运行一下看看:

    QQ截图20120912093630

    奇怪,这是为什么会变成这样呢,这里说一下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,去掉之后运行是下面这个样子的:

    QQ截图20120912094010

    这个bug的解决方法,也很简单,就是在AppDelegate里初始化一下Font就行了,这是因为内部的处理机制造成的。

    CCLabelTTF a = CCLabelTTF.labelWithString("0", "Arial", 0);

    加入上面的代码就可以,不用添加进去,现在运行看看:

    QQ截图20120912094032

    是不是帅多了?也许现在迫不及待的赶紧弄下一个场景,先打住,现在聊聊更加重要的话题:

    庞大的资源  纹理图片优化 plist

    现在打开你的工程目录找到bin下面所编译的程序,看看Content里(Content是输出工程的内容集合,你所见的都将会打包到XAP中)输出的XNB文件吧:

    QQ截图20120912094321

    现在,你能忍吗?其实原图不打包才400多KB,为什么转换之后就变成这么夸张了呢,因为XNA对资源内容都会自行编译输出,这是为了方便自己,同时将不规格的资源内容编译成规格的,这方面如果说多了就会涉及到图像渲染的细节,这么说吧,对于图像渲染显示而言,它们其实只认2的N次幂长宽的图像,无论是程序还是硬件,它的输入和输出都遵循这个规则,所以,你的精美小图片不管用什么存储最终都会变成统一规格。

    一种方法是通过图像纹理的模式修正,将其变成2的N次幂长宽的图像,请看下图:

    image

    你的所有的图像都会默认为color格式,所以很悲催的事实就是将面临超大的图像素材体积(内部还给你扩展成了2的N次幂),DxtCompressed格式则可以大大的减小图像体积,但是DxtCompressed对图像有一定的要求,最基本的要求是:2的N次幂宽高

    对于图像资源,很难有正好的符合,刻意的制作就会代码N多代码的修正,我们利用cocos2d的特性来解决,在cocos2d有一种将很多图片保存成为一张大图片,然后独取出来单独使用,这个方法就是plist的图片帧文件,它能极大的减小图片体积,最重要的是大图就能符合2的N次幂宽高的要求了。

    TexturePackerGUI是专门制作cocos2d plist文件的软件,这个软件最好的优势是有Windows版本的(有很多优秀的工具都在IOS运行),下面是简单的使用方法:

    先打开TexturePackerGUI,将前面的开始界面素材拖入到窗口中。

    QQ截图20120912223502

    建议将DataFormat改成cocos2d-0.99.4,然后点击Publish按钮,保存为GameUI01.plist,浏览位置就会发现多出一个GameUI01.png,它们之间就是对应的,现在我们在程序里使用它们,将其添加到Content工程里,然后做如下两个修改:

    1、修改一下GameUI01.png的Content Processor内Textrue Format属性为DxtCompressed。

    2、修改GameUI01.plist的输入和输出管线,因为plist需要cocos2dxna的独特的内容管线,所以先添加引用:

    image

    然后选择GameUI.plist属性,将输入和输出的管线修改:

    image

    现在编译一下看看,呵呵,你会发现一个错,这个错是关于重复名称的,所以你需要将生成的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软件,可以在网上搜索到使用。

    本想在本次写完切换的,看了看内容已经够多了,还是下一篇完成吧:)

  • 相关阅读:
    基本STRUTS标签-学习笔记-Logic标签
    Static的使用
    模板template
    iostream与iostream.h的区别
    数据库连接池
    canvas基础
    javascript面试题集
    ES6新特性学习
    原型和原型链
    css为tbody或者li奇数偶数行样式
  • 原文地址:https://www.cnblogs.com/nowpaper/p/2682606.html
Copyright © 2020-2023  润新知