免責聲明:本文章由fengyun1989創作,采用知識共享署名-非商業性使用-相同方式共享 2.5 中國大陸許可協議進行許可。
寫在前面:最近兩個月比較忙,很久沒更新教程了。這么些日子,發生了不少事,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動作。這樣就能產生地鼠從洞中鑽出的視覺效果了。
現在來下載需要的圖片;http://dl.dbank.com/c0tayrr384
開始吧:
新建一個工程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(@"images/background"); background.position = new CCPoint(winSize.width / 2, winSize.height / 2); this.addChild(background, -3); CCSprite grassUpper = CCSprite.spriteWithFile(@"images/grass_upper"); grassUpper.position = new CCPoint(winSize.width / 2, winSize.height - grassUpper.contentSize.height / 2); this.addChild(grassUpper, -2); CCSprite grassMid = CCSprite.spriteWithFile(@"images/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(@"images/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(@"images/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 = 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(@"images/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下
- 添加很棒的音效
本次工程代碼下載:http://dl.dbank.com/c0bgua6l79
