• 热门专题

cocos2d-XNA游戏开发之山寨《Flapy Bird》(一)

作者:Neoyee  发布日期:2014-03-25 20:01:22
Tag标签:山寨  
  •   最近在看cocos2d开发,想找个游戏练练手,碍于没有策划能力,只能从山寨做起。目前最火的游戏,莫过于是这个像素鸟《Flapy Bird》了,下面就开始山寨它吧。

    开发环境

    系统:Windows8

    IDE:Visual Studio 2012

    资源文件

    随便那个网站下载一个flapybird的apk(下载地址:http://app.suning.com/d.php?pack=com.dotgears.flappybird),改后缀名为.rar,解压之后就能找到游戏引用的资源。

    打开assets\gfx,会找到一张atlas.png,包含了所有的图片资源,sound中是声音资源。

    项目搭建

    因为是学习项目,就自己搭建cocos框架,不使用cocos模版。新建项目,选择XNAGame->WindowsPhone游戏。

    添加AppDelegate.cs类,继承 CCApplication,添加构造函数,重写applicationDidFinishLaunching方法;

    public class AppDelegate : CCApplication
        {
            public AppDelegate(Game game, GraphicsDeviceManager graphics)
                : base(game, graphics)
            {
                CCApplication.sm_pSharedApplication = this;
            }
    
    
            public override bool applicationDidFinishLaunching()
            {
                CCDirector pDirector = CCDirector.sharedDirector();
                pDirector.setOpenGLView();
    
                pDirector.DisplayFPS = true;
                pDirector.deviceOrientation = ccDeviceOrientation.CCDeviceOrientationPortrait; ;
                pDirector.animationInterval = 1.0 / 60;
    
                CCScene pScene = new CCScene();
                pDirector.runWithScene(pScene);
                return base.applicationDidFinishLaunching();
            }
        }
    

    修改Game1.cs构造函数,添加代码:

    public Game1()
            {
                graphics = new GraphicsDeviceManager(this);
                Content.RootDirectory = "Content";
    
                this.graphics.IsFullScreen = true;
                // Windows Phone 的默认帧速率为 30 fps。
                TargetElapsedTime = TimeSpan.FromTicks(333333);
    
                // 延长锁定时的电池寿命。
                InactiveSleepTime = TimeSpan.FromSeconds(1);
    
                CCApplication application = new AppDelegate(this, graphics);
                this.Components.Add(application);
            }
    

      

    添加场景(CCScene)

    我们仔细观察游戏可以把游戏分为2个场景:

    1.菜单场景

    2.游戏场景

    由于我们在AppDelegate创建了一个CCScene,可以用它来作为菜单场景,再新建一个GamePlayScene作为游戏场景(也可以自己新建一个MenuScene作为菜单场景)。

    添加层(CCLayer)

    游戏可以大致分为以下个层:

    1.背景层(BackgroundLayer)

    2.移动的道路层(RoadLayer)

    3.游戏层(GamePlayLayer)

    4.菜单层(MainLayer)

    在菜单场景中,我们需要用到BackgroundLayer,RoadLayer和MainLayer。修改AppDelegate.cs代码:

    public override bool applicationDidFinishLaunching()
            {
                CCDirector pDirector = CCDirector.sharedDirector();
                pDirector.setOpenGLView();
    
                pDirector.DisplayFPS = true;
                pDirector.deviceOrientation = ccDeviceOrientation.CCDeviceOrientationPortrait; ;
                pDirector.animationInterval = 1.0 / 60;
    
                CCScene pScene = new CCScene();
                pScene.addChild(BackgroundLayer.node(), (int)LayerTags.Background, (int)LayerTags.Background);
                pScene.addChild(RoadLayer.node(), (int)LayerTags.Road, (int)LayerTags.Road);
                pScene.addChild(MainLayer.node(), (int)LayerTags.Game, (int)LayerTags.Game);
                pDirector.runWithScene(pScene);
                return base.applicationDidFinishLaunching();
            }
    

      

    public enum LayerTags
        {
            Background = 0,
            Game = 1,
            Road = 2
        }
    

      

    背景层(BackgroundLayer)

     BackgroundLayer继承自CCLayer,重写静态方法node;

    public static new CCLayer node()
            {
                BackgroundLayer ret = new BackgroundLayer();
                if (ret.init())
                {
                    return ret;
                }
    
                return null;
            }
    

    下面我们就需要画背景图片了,重写init方法

    首先我们需要算出资源图片与屏幕大小的缩放比例:

    //288,511是背景图的大小
    sX = CCDirector.sharedDirector().getWinSize().width / 288f; 
    sY = CCDirector.sharedDirector().getWinSize().height / 512f;
    

    由于此游戏的资源图片是一整张大图,所以我们需要根据区域进行读取,观察资源图片我们可以发现,存在2个背景图片,看来需要随机出现一个背景图片,完整init代码:

    public override bool init()
            {
                sX = CCDirector.sharedDirector().getWinSize().width / 288f;
                sY = CCDirector.sharedDirector().getWinSize().height / 512f;
                Random random = new Random();
                int number = random.Next(0, 2);
                CCRect ccRect;
                if (number == 0)
                {
                    ccRect = new CCRect(0, 0, 288, 512);
                }
                else
                {
                    ccRect = new CCRect(292, 0, 288, 512);
                }
                CCSprite backgroundCcSprite = CCSprite.spriteWithFile("Images/background", ccRect);
                backgroundCcSprite.position = new CCPoint(240, 400);
                backgroundCcSprite.scaleY = sY;
                backgroundCcSprite.scaleX = sX;
                addChild(backgroundCcSprite);
    
                
                return base.init();
    
            }
    

    效果如下:

     道路层(RoadLayer)

    与背景层类似,继承自CCLayer并重写方法node()、init();

    public static new CCLayer node()
            {
                RoadLayer ret = new RoadLayer();
                if (ret.init())
                {
                    return ret;
                }
    
                return null;
            }
    
            public override bool init()
            {
                sX = CCDirector.sharedDirector().getWinSize().width / 288f;
                sY = CCDirector.sharedDirector().getWinSize().height / 512f;
    
                CCSprite downRoadCcSprite1 = CCSprite.spriteWithFile("Images/background", new CCRect(584, 0, 336, 112));
                downRoadCcSprite1.position = new CCPoint(240, 72);
                downRoadCcSprite1.scaleX = sX;
                downRoadCcSprite1.scaleY = sY;
                addChild(downRoadCcSprite1, 1, (int)SpriteTags.Road);
    
                return base.init();
            }

    让道路动起来

    此处我采用的是添加2个道路CCSprite,像小火车一样跟着,每动一帧,2个道路的坐标减少4,当第一个的x坐标等于0之后,将其放到第二个的后面,也就是x坐标等480(屏幕宽度)。

    添加一个schedule定时器执行更新道路坐标方法,代码如下:

    public override bool init()
            {
                sX = CCDirector.sharedDirector().getWinSize().width / 288f;
                sY = CCDirector.sharedDirector().getWinSize().height / 512f;
    
                downRoadCcSprite1 = CCSprite.spriteWithFile("Images/background", new CCRect(584, 0, 336, 112));
                downRoadCcSprite1.position = new CCPoint(240, 72);
                downRoadCcSprite1.scaleX = sX;
                downRoadCcSprite1.scaleY = sY;
                addChild(downRoadCcSprite1, 1, (int)SpriteTags.Road);
    
                downRoadCcSprite2 = CCSprite.spriteWithFile("Images/background", new CCRect(584, 0, 336, 112));
                downRoadCcSprite2.position = new CCPoint(480, 72);
                downRoadCcSprite2.scaleX = sX;
                downRoadCcSprite2.scaleY = sY;
                addChild(downRoadCcSprite2, 1, (int)SpriteTags.Road);
    
                this.schedule(updateDownRoad, 0.01f);
                return base.init();
            }
            private void updateDownRoad(float dt)
            {
                downRoadCcSprite1.position = new CCPoint(downRoadCcSprite1.position.x - 4, downRoadCcSprite1.position.y);
                if (downRoadCcSprite1.position.x == 0)
                {
                    downRoadCcSprite1.position = new CCPoint(480, downRoadCcSprite1.position.y);
                }
                downRoadCcSprite2.position = new CCPoint(downRoadCcSprite2.position.x - 4, downRoadCcSprite2.position.y);
                if (downRoadCcSprite2.position.x == 0)
                {
                    downRoadCcSprite2.position = new CCPoint(480, downRoadCcSprite2.position.y);
                }
            }
    

    添加菜单

    开始我做菜单的方法和上面一样从大图中截取图片生成CCMenuItemSprite,但是加入后发现菜单并非是一直显示的,不知道哪里设置出了问题:

    CCSprite testCcSprite = CCSprite.spriteWithFile("Images/background", new CCRect(705, 235, 107, 58));
                testCcSprite.scaleX = sX;
                testCcSprite.scaleY = sY;
                CCMenuItemSprite testMenuItemSprite = CCMenuItemSprite.itemFromNormalSprite(testCcSprite, testCcSprite);
                CCMenu testmenuOperate = CCMenu.menuWithItems(testMenuItemSprite);
                testmenuOperate.position = new CCPoint(240, 205);
                this.addChild(testmenuOperate);
    

    效果:

    没办法了,只能切成单个图片,然后用另外一种方式试试,发现居然可行,求解!!!

    CCMenuItemImage rateCcMenuItemSprite = CCMenuItemImage.itemFromNormalImage("Images/rate", "Images/rate_pressed", this, rateCallback);
                rateCcMenuItemSprite.scaleX = sX;
                rateCcMenuItemSprite.scaleY = sY;
    
                CCMenu menuRate = CCMenu.menuWithItems(rateCcMenuItemSprite);
                menuRate.position = new CCPoint(240, 350);
                this.addChild(menuRate);
    
                CCMenuItemImage startCcMenuItemSprite = CCMenuItemImage.itemFromNormalImage("Images/play", "Images/play_pressed", this, playCallback);
                startCcMenuItemSprite.scaleX = sX;
                startCcMenuItemSprite.scaleY = sY;
    
                CCMenuItemImage scoreCcMenuItemSprite = CCMenuItemImage.itemFromNormalImage("Images/rank", "Images/rank_pressed", this, rankCallback);
                scoreCcMenuItemSprite.scaleX = sX;
                scoreCcMenuItemSprite.scaleY = sY;
    
                CCMenu menuOperate = CCMenu.menuWithItems(startCcMenuItemSprite, scoreCcMenuItemSprite);
                menuOperate.alignItemsHorizontallyWithPadding(30);
                menuOperate.position = new CCPoint(240, 205);
                this.addChild(menuOperate);
    

    CCMenuItemImage startCcMenuItemSprite = CCMenuItemImage.itemFromNormalImage("Images/play", "Images/play_pressed", this, playCallback);第一个参数为默认图片,第二个为按下时候图片,playCallback为按下的处理事件

      

    然后添加Logo

    CCSprite logoCcSprite = CCSprite.spriteWithFile("Images/background", new CCRect(700, 177, 185, 55));
                logoCcSprite.position = new CCPoint(240, 550);
                logoCcSprite.scaleX = sX;
                logoCcSprite.scaleY = sY;
                addChild(logoCcSprite);
    

    添加会动的小鸟

    此处采用CCAnimation进行绘制小鸟的动画,在init中调用initActiveBird()

    private void initActiveBird()
            {
                CCTexture2D texture = CCTextureCache.sharedTextureCache().addImage("Images/background");//2D纹理
    
                CCSpriteFrame birFrame6 = CCSpriteFrame.frameWithTexture(texture, new CCRect(117, 976, 40, 50));
                CCSpriteFrame birFrame7 = CCSpriteFrame.frameWithTexture(texture, new CCRect(117, 975, 40, 50));
                CCSpriteFrame birFrame8 = CCSpriteFrame.frameWithTexture(texture, new CCRect(117, 974, 40, 50));
                CCSpriteFrame birFrame9 = CCSpriteFrame.frameWithTexture(texture, new CCRect(117, 975, 40, 50));
                CCSpriteFrame birFrame10 = CCSpriteFrame.frameWithTexture(texture, new CCRect(117, 976, 40, 50));
                CCSpriteFrame birFrame0 = CCSpriteFrame.frameWithTexture(texture, new CCRect(61, 982, 40, 50));
                CCSpriteFrame birFrame1 = CCSpriteFrame.frameWithTexture(texture, new CCRect(61, 981, 40, 50));
                CCSpriteFrame birFrame2 = CCSpriteFrame.frameWithTexture(texture, new CCRect(61, 980, 40, 50));
                CCSpriteFrame birFrame3 = CCSpriteFrame.frameWithTexture(texture, new CCRect(61, 979, 40, 50));
                CCSpriteFrame birFrame4 = CCSpriteFrame.frameWithTexture(texture, new CCRect(61, 978, 40, 50));
                CCSpriteFrame birFrame5 = CCSpriteFrame.frameWithTexture(texture, new CCRect(61, 977, 40, 50));
                CCSpriteFrame birFrame11 = CCSpriteFrame.frameWithTexture(texture, new CCRect(5, 977, 40, 50));
                CCSpriteFrame birFrame12 = CCSpriteFrame.frameWithTexture(texture, new CCRect(5, 978, 40, 50));
                CCSpriteFrame birFrame13 = CCSpriteFrame.frameWithTexture(texture, new CCRect(5, 979, 40, 50));
                CCSpriteFrame birFrame14 = CCSpriteFrame.frameWithTexture(texture, new CCRect(5, 980, 40, 50));
                CCSpriteFrame birFrame15 = CCSpriteFrame.frameWithTexture(texture, new CCRect(5, 981, 40, 50));
                CCSpriteFrame birFrame16 = CCSpriteFrame.frameWithTexture(texture, new CCRect(5, 982, 40, 50));
                CCSprite birdCcSprite = CCSprite.spriteWithSpriteFrame(birFrame0);
                birdCcSprite.position = new CCPoint(240, 430);
                birdCcSprite.scaleX = sX;
                birdCcSprite.scaleY = sY;
                addChild(birdCcSprite);
    
                List<CCSpriteFrame> animFrames = new List<CCSpriteFrame>();
                animFrames.Add(birFrame0);
                animFrames.Add(birFrame1);
                animFrames.Add(birFrame2);
                animFrames.Add(birFrame3);
                animFrames.Add(birFrame4);
                animFrames.Add(birFrame5);
                animFrames.Add(birFrame6);
                animFrames.Add(birFrame7);
                animFrames.Add(birFrame8);
                animFrames.Add(birFrame9);
                animFrames.Add(birFrame10);
                animFrames.Add(birFrame11);
                animFrames.Add(birFrame12);
                animFrames.Add(birFrame13);
                animFrames.Add(birFrame14);
                animFrames.Add(birFrame15);
                animFrames.Add(birFrame16);
                CCAnimation animation = CCAnimation.animationWithFrames(animFrames, 0.03f);
                CCAnimate animate = CCAnimate.actionWithAnimation(animation, true);
                CCActionInterval seq = (CCActionInterval)(CCSequence.actions(animate));
                birdCcSprite.runAction(CCRepeatForever.actionWithAction(seq));
            }
    

     

    场景切换

    在点击开始按钮时候,我们需要进行场景切换,跳到游戏场景,为playCallback添加实现

     private void playCallback(CCObject sender)
            {
                GamePlayScene gamePlayScene = new GamePlayScene();
                gamePlayScene.addChild(BackgroundLayer.node(), (int)LayerTags.Background, (int)LayerTags.Background);
                gamePlayScene.addChild(RoadLayer.node(), (int)LayerTags.Road, (int)LayerTags.Road);
                gamePlayScene.addChild(GamePlayLayer.node(), (int)LayerTags.Game, (int)LayerTags.Game);
                float t = 0.8f;
                CCTransitionScene reScene = CCTransitionFade.transitionWithDuration(t, gamePlayScene);
                CCDirector.sharedDirector().replaceScene(reScene);
            }

    *******************************************

    至此,第一屏已经山寨完毕,楼主去写第二屏算法去了。

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规