写在前面:最近两个月比较忙,很久没更新教程了。这么些日子,发生了不少事,WP8发布了。我的T8788也被彻底抛弃了。。。win8也RP版了。前景未卜啊。肯定不少人在迷茫了吧。我觉得呢,都是浮云,语言只是工具,能够一通百通才是王道,微软不行大不了换IOS,Android。接下来的一段时间,估计会写些win8的教程。我感觉win8和WP8有种莫名的联系,不过也道不清说不明。反正就顺着感觉来了。

本次教程写一个简单的打地鼠游戏。如果你对cocos2d-x编程不了解,可以先阅读《用cocos2d-x做一个简单的windows phone 7游戏》系列文章。不过,如果你有相关的经验就另当别论了。

程序截图:

 

思路简介:

打地鼠主要是问题就在于地鼠出头和打地鼠的点击处理。地鼠出头有两种方法,一种是用动画,一种是用Z轴的纵向效果。动画效果的方法Nowpaper前段时间就写了这么一篇《Cocos2d-x for WindowsPhone:开发一个打地鼠游戏》,我想就不在这里啰嗦了。懒得再将这些重复的内容在做一遍。这里就介绍下Z轴的方法。



只要把前景分为3块。分为上中下三块,在洞的中心分开。添加到层的时候设置Z轴,最下的最前,最上的最后。最后后的设置一块黑色的背景。两块图之间留着空间来让地鼠Sprite进行move动作。这样就能产生地鼠从洞中钻出的视觉效果了。

现在来下载需要的图片;/data/p_w_upload/portal/et2/201207/ET35158120912203.zip

开始吧:

新建一个工程cocos2d的工程,命名为cocos2dWhacAMoleDemo。当然,因为是练习项目,所以OpenXLive没有用到。就去掉那个勾。然后修复引用。这些操作做了很多次了。不懂的建议看下以前的文章。

  然后再Classes文件夹添加一个类。命名为AttackMoleScene.cs,使之继承于CCScene。修改代码如下:

 

namespace cocos2dWhacAMoleDemo.Classes{    class AttackMoleScene:CCScene    {        public AttackMoleScene()        {            this.addChild(AttackMoleLayer.node());        }    }    class AttackMoleLayer : CCLayer    {        public override bool init()        {            if (!base.init())                return false;            CCSize winSize = CCDirector.sharedDirector().getWinSize();            CCSprite background = CCSprite.spriteWithFile(@"p_w_picpaths/background");            background.position = new CCPoint(winSize.width / 2, winSize.height / 2);            this.addChild(background, -3);            CCSprite grassUpper = CCSprite.spriteWithFile(@"p_w_picpaths/grass_upper");            grassUpper.position = new CCPoint(winSize.width / 2, winSize.height - grassUpper.contentSize.height / 2);            this.addChild(grassUpper, -2);            CCSprite grassMid = CCSprite.spriteWithFile(@"p_w_picpaths/grass_mid");            grassMid.position = new CCPoint(winSize.width / 2,                winSize.height - grassUpper.contentSize.height - grassMid.contentSize.height / 2);            this.addChild(grassMid, 0);            CCSprite grassLower = CCSprite.spriteWithFile(@"p_w_picpaths/grass_lower");            grassLower.position = new CCPoint(winSize.width / 2, grassLower.contentSize.height / 2);            this.addChild(grassLower, 2);            return true;        }        public new static AttackMoleLayer node()        {            AttackMoleLayer layer = new AttackMoleLayer();            if (layer.init())                return layer;            return null;        }    }}

 

上面做了些什么呢,在层里面添加了前景。三块,细心的朋友注意到了。我addChild的时候,Z轴的参数都不一样。背景在最后,所以Z轴的值最小。每两块间留一个位置给地鼠冒头。前景的位置也是设置成上中下三个位置。这样,从Z轴的上头看下就能正好成一整块前景。

现在修改AppDelegate的applicationDidFinishLaunching方法:

            //CCScene pScene = cocos2dWhacAMoleDemoScene.scene();            AttackMoleScene pScene = new AttackMoleScene();            //run            pDirector.runWithScene(pScene);

现在可以执行了。就可以看到不错的前景了。

 

那么现在来添加一个地鼠来冒一下头试试吧。

在层的init方法上面添加:

            CCSprite mole = CCSprite.spriteWithFile(@"p_w_picpaths/mole_1");            mole.position = new CCPoint(155,30);            var move = CCMoveBy.actionWithDuration(2, new CCPoint(0, 100));            var action = CCRepeat.actionWithAction(CCSequence.actions(move, move.reverse()), 5);            mole.runAction(action);            this.addChild(mole, 1);

添加一个地鼠到层中,并且设置它在左下角的洞里进行Move来回运动。关于这个坐标(155,30)是怎么算出来的,我用画图工具打开grass.png这个文件,用鼠标来大概获取坐标,然后用笔算下坐标。需要注意的是,cocos2d-x里面的坐标原点在左下角。而window的是在左上角。

现在编译运行,就能看到一个地鼠来回冒头了。

 

让地鼠随机冒头

我们先来思考下接下来的怎么做,怎么保存所以的地鼠精灵,怎么确定初始化坐标,怎么判断地鼠被打,然后让他消失,怎么确定洞里面有地鼠而不至于重复添加。

我的方法是全部用数组来解决。比较简单。

添加以下的声明到层:

 

        int[,] moleValue = http://www.cnblogs.com/fengyun1989/archive/2012/07/09/new int[2, 3] { { 0, 0, 0 }, { 0, 0, 0 } };        CCSprite[,] moles = new CCSprite[2, 3];        int[] initPositionX = new int[3] { 155, 400, 640 };        int[] initPositionY = new int[2] {30, 260};

 

上面的moleValue记录的是当前洞里有没有地鼠,1就是有,0就是没有。moles记录当前所有冒头地鼠的引用。最后两个是初始化坐标,3*2=6. 这些坐标都是我通过画图工具来计算出来的。

现在注释到上面的单个地鼠冒头的代码。往层里面添加方法:

       void addMole(float dt)        {            Random r = new Random();            int i = r.Next() % 3;            int j = r.Next() % 2;            if (moleValue[j, i] == 0)            {                moles[j, i] = CCSprite.spriteWithFile(@"p_w_picpaths/mole_1");                moles[j, i].position = new CCPoint(initPositionX[i], initPositionY[j]);                var move = CCMoveBy.actionWithDuration(2, new CCPoint(0, 100));                var action = CCSequence.actions(move, move.reverse()                    , CCCallFuncN.actionWithTarget(this, spriteMoveDone));                moles[j, i].runAction(action);                moleValue[j, i] = 1;                if (j == 0)                    this.addChild(moles[j, i], 1);                else                    this.addChild(moles[j, i], -1);            }        }        void spriteMoveDone(object sender)        {            CCSprite sprite = sender as CCSprite;            for (int i = 0; i < 3; i++)            {                for (int j = 0; j < 2; j++)                {                    if (moles[j, i] == sprite)                    {                        moleValue[j, i] = 0;                        break;                    }                }            }            this.removeChild(sprite, true);        }

并且添加一行到init方法

 

this.schedule(addMole, 1.0f);

我们修改地鼠变为只是上下Move一次。并且在退回后调用回调函数移除该sprite。设置该位置的moleValue值为0.现在就能看见地鼠不怕死的不断冒头了。

 

打地鼠

既然地鼠都不怕死的冒出来了。不打貌似很不爽的样子,但是,现在点击屏幕,没人任何反应。。。因为我们还没有对点击进行注册和处理。

   那么怎么判断是点击了地鼠呢。我设定这么一个范围算是点击了地鼠。

 

由于地鼠初始化在框的下面,其坐标的X和在这个黑色框下边的中点坐标X一样。Y值+70才算和这个黑色框下边的中点的坐标Y值一样。

现在添加一个方法来处理触点坐标:

        private void handleTouchPosition(CCPoint touch)        {            for (int i = 0; i < 3; i++)            {                for (int j = 0; j < 2; j++)                {                    float tempX = initPositionX[i] - touch.x;                    if ((tempX < 80 && tempX > -80) && (initPositionY[j] + 150 - touch.y > 0 && initPositionY[j] + 70 < touch.y))                    {                        if (moleValue[j, i] == 1)                        {                            if (moles[j, i] != null)                            {                                this.removeChild(moles[j, i], true);                            }                            moleValue[j, i] = 0;                            moles[j, i] = null;                        }                        return;                    }                }            }        }

这样,遍历所有的洞,判断点击是否是这个洞。然后判断现在是否有地鼠,有地鼠就把地鼠移除。

现在在init方法中注册触摸事件:

this.isTouchEnabled = true;

然后重载ccTouchesEnded方法:

        public override void ccTouchesEnded(List<CCTouch> touches, CCEvent event_)        {            foreach (var touch in touches)            {                CCPoint touchLocation = touch.locationInView(touch.view());                touchLocation = CCDirector.sharedDirector().convertToGL(touchLocation);                touchLocation = this.convertToNodeSpace(touchLocation);                handleTouchPosition(touchLocation);            }        }

这个方法先把坐标转换,再处理坐标。现在运行,可以看到地鼠被打死了。

何去何从

现在,我们已经拥有了一个不错的打地鼠游戏。是不是觉得少了点什么呢。。

        考虑拓展地鼠被打的动作,加个锤子或者什么的。另外,可以添加地鼠被打后的表情,这都可以用Action可以实现
        把硬编码的地鼠重构出来,添加多个关卡
        去试试用动画来制作地鼠冒头
        增加更多种类的地鼠,比如说有些地鼠可以挨打2下
        添加很棒的音效