做游戲是個很好玩的事情,由于興趣我最近也在學習如何用android做游戲。順便它選擇了植物大戰僵尸來當我的嵌入式作業 。熬了兩天兩夜終于把它完成了。這個過程從學習調研到寫代碼的各種心塞到完工,花了很多時間,也花了很多精力,但覺得是值得的。本文并不是講解植物大戰僵尸是怎么做的,而是講解CoCos2d_android常用的基礎知識,當然只要知道這些知識也就能夠能完成這個游戲,最后會把代碼貼出。先看下效果圖:


、
### 一.Cocos2d_android介紹
Cocos2d是一個大家庭,包括Cocos2d-iphone,Cocos2d-x,Cocos2d-javascript等。而在國內,Cocos2d-x則相對領先。在中國的2D手機游戲開發中,Cocos2d-x引擎的份額超過70%。不同家庭成員之間只是語言不同,而實現的接口名稱都相同。所以只要學習一個,其它的就都比較好理解了。本文講的是Coscos2d_android,因為它是用java實現的,所以對我來說學起來比較快。
### 二.Cocos2d_android架構

如上圖,Cocos2d這游戲引擎主要由圖形引擎(Graphic),聲音引擎(Audio),物理引擎(Box2d),腳本庫以及相關語言等組成。我們重點關注開發過程中需要注意的。先看一張Cocos2d_android的代碼結構圖:

對于Cocos2d_android只要關注四個部分, CCDirector(導演),CCScene(場景),CCLayout(幕布)以及CCSprite(精靈)。我們可以把它當成在拍電影,顧名思義可以看出它們的作用:
CCDirector:電影中的導演,肯定是負責整部電影拍攝的,它有三個功能,管理CCScene,開線程執行SurfaceView中的繪制行為,設置游戲屬性。
CCScene:電影中的場景,當然包括人和背景。可以理解它是根View,layer都必須建立在它之上,有點類似activity與fragment的關系。
CCLayer:場景中的部分圖層,離用戶最近的一層。游戲過程中始終只有一個layer能獲得焦點。每個動作都必須建立在layer上。
CCSprite:精靈,這個可以理解為activity中的一個控件。就是最小的一部分了。平時控制最多的也就是它,所以要重點關注。
### 三.四大組成部分用法
其它先不說,首先你要用Cocos2d_android,你就應該先把包導進來(可以在我的工程下的libs中找到)。接下來講解下上面講的四部分如何在代碼里面用。首先是CCDirector,直接看MainActivity中CCDirector的設置代碼:
~~~
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CCGLSurfaceView surfaceView = new CCGLSurfaceView(this);
setContentView(surfaceView);
director = CCDirector.sharedDirector();
director.attachInView(surfaceView);//開線程
director.setScreenSize(480, 320);
director.setDeviceOrientation(CCDirector.kCCDeviceOrientationLandscapeLeft);//橫屏
director.setDisplayFPS(true);//不顯示幀率
CCScene scene = CCScene.node();
scene.addChild(new WelComeLayer());
//導演管理場景
director.runWithScene(scene);
}
@Override
protected void onResume() {
director.onResume();
super.onResume();
}
@Override
protected void onPause() {
director.onPause();
super.onPause();
}
@Override
protected void onDestroy() {
director.end();
super.onDestroy();
}
~~~
CCGLSurfaceView繼承著SurfaceView,由此可見游戲引擎是用SurfaceView做的。CCDirector是一個單例,調用sharedDirector來獲取它,保證全局只有一個CCDirector。初始化完后就要開始工作了,首先attachInView與surfaceView連接,感興趣的可以進去看下attachInView源碼,它跟我們平時使用surfaceView很相似,也是開了個線程,然后在幕布上畫圖像。這里主要是講使用,就不翻源碼了。setDeviceOrientation設置屏幕橫屏。setDisplayFPS設置為true時就會在游戲左下角顯示幀率,這個只是在開發時使用。最后很關鍵的就是初始化一個CCScene,并調用runWithScene把場景加進去。這樣CCDirector的初始工作就結束了。
接下來看CCScene,它是根View,初始時經過runWithScene加入到CCDirector中,不同游戲界面可以理解為不同layer,切換layer可以理解為切換activity一樣,而切換的代碼如下,基本可以看成是固定格式的。
~~~
CCScene scene = CCScene.node();
scene.addChild(new FightLayer());
CCFadeTransition transition = CCFadeTransition.transition(0.5F, scene);
//替換場景
CCDirector.sharedDirector().replaceScene(transition);
~~~
transition是一個切換動畫,CCFadeTransitiion只是切換動畫的一種,具體可以察看api。
好,我們要玩游戲就要有界面,界面畫在哪上面?xml,還是activity。那么接下來這位成員就派上它的用場了。layer需要我們自己來實現,它要繼承自CCLayer,如以下是自定義的layer:
~~~
public class WelComeLayer extends CCLayer {
public WelComeLayer(){
init();
}}
~~~
只要把你自己的實現寫在init()方法中就可以了。什么時候被調用就要看什么時候它被addChild到scene中。layer中就可以處理很多事情,包括地圖的加載,音樂的播放,精靈的移動等。這些后面會細講。最后就是精靈啦。
CCSprite是用的最多的,一個僵尸可以是一個精靈,一張圖片一段文字都可以是一個精靈。精靈的加載如下:
~~~
choseContainer = CCSprite.sprite("fight_chose.png");
choseContainer.setAnchorPoint(0, 1);
choseContainer.setPosition(0, cgSize.height);
this.addChild(choseContainer,0,1);
~~~
這里是把assets下的一張圖片當作精靈,setAnchorPoint是設置錨點,(0,1)就是圖片的左上角,相當于圖片釘在左上角上,移動旋轉時它都為中心。setPosition不用說,就是設置精靈的位置啦。然后調用layer的addChild就把它加載進來了。這里它有三個參數,第一個是精靈,第二個是它的層數,0是最底層的,如果想把它置于上層,就給它設置一個值,值越大層數越高,就越不會被覆蓋。最后一個參數是tag,設置了它就可以在其它地方通過tag來獲取這個精靈,類似于findViewById(),獲取代碼如下:
~~~
CCSprite c = layer.getChildByTag(1);
~~~
注意上面的layer必須是你定義精靈所在的layer中。那么如何在layer中監聽點擊事件呢,看以下代碼:
~~~
//設置物體的觸發事件
@Override
public boolean ccTouchesBegan(MotionEvent event) {
// TODO Auto-generated method stub
CCSprite sprite = (CCSprite) this.getChildByTag( TAG_X);
//轉成opengl下的坐標點
CGPoint cgPoint = this.convertTouchToNodeSpace(event);
boolean flag = CGRect.containsPoint(sprite.getBoundingBox(), cgPoint);
if(flag){
//設置透明度
sprite.setOpacity(100);
//設置是否可見
sprite.setVisible( false);
//刪除自己
sprite.removeSelf();
}
return super.ccTouchesBegan(event);
}
~~~
類似于OnEventTouch(),這里有一個知識點,就是android平時的習慣是把屏幕左上角當坐標原點,向下的y正,向右是x正。但是在Cocos2d中不一樣,你必須把它轉成openGl的習慣,也就是左下角是坐標,向上是y正,向右是x正。轉化也有api,如上面的convertTouchToNodeSpace()就是把android的point轉成OpenGL下的Point。
### 四,加載資源文件
講到這里,我假設你之前的都己經明白了,也能在不同界面上顯示不同的sprite了,那接下來我們就要對游戲場景進行優化,首先光一些精靈肯定不行,肯定要有背景圖,而且游戲嘛,肯定也要有音樂。那首先來講講地圖的加載吧。
其實地圖加載我認為一點都不簡單,別以為地圖只是一張圖片,如果是張圖片,那游戲開發過程中要定位位置怎辦。其實在游戲中有一個格式的文件很見,.tmx文件,它包括地圖上某些你標記的點的信息。這樣的圖片用文本編輯器打開如下:
~~~
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="orthogonal" width="14" height="6" tilewidth="46" tileheight="54">
<tileset firstgid="1" name="bk1" tilewidth="46" tileheight="54">
<image source="bk1.jpg" width="678" height="331"/>
</tileset>
<layer name="block" width="14" height="6">
<data encoding="base64" compression="zlib">
eJwNw4lSQQEAAMAXEZWEpKjooEShkhJdEkmS+v9vaXdml4IgCBl22YhRV4wZd9U11024YdJNU6bNuGXWbXPuuGvegnvue2DRkoceeeyJZSueembVc2vWvfDShk1bXnntjW1v7XjnvV0f7Nn30SefffHVgW8OfXfk2A8nfjr1y5nfzv1x4a9//gNAug3z
</data>
</layer>
<objectgroup name="road" width="14" height="6" visible="0">
<object x="473" y="96"/>
<object x="474" y="306"/>
<object x="23" y="303"/>
</objectgroup>
</map>
~~~
它會被解析成一個xml格式的文件,里面記錄了地圖長寬,及長寬分為幾塊,以及一些標記點的集合。如上面name為“road”的集合。看到這你是不是嚇到了,難道每個地圖都要自己手寫?這肯定是不可能的。這里介紹一款小軟件,tiled([下載鏈接](http://u.download.csdn.net/upload/success))。它可以方便的進行地圖標記,顯示如下圖:

如果你想改變背景圖的樣子,可以用上邊欄的填充工具等進行繪制,如果想定點就新建一個對象層,如同圖中的road。再用工具欄上的創建對象按鈕在地圖上定點,記住定點的順序是有講究的,先確定的點會存在前面,這個待會解析時會說,可以創建多個對象層,起的名字就是文件中objectgroup的name屬性對應的名字。圖片制作完成后保存就自動更改為.tmx格式。把它放到assets文件下,就可以加載它了,來看下加載的代碼:
~~~
map = CCTMXTiledMap.tiledMap("map_day.tmx");
map.setAnchorPoint(0.5f,0.5f);
CGSize contentSize = map.getContentSize();
//左移右移一半
map.setPosition(contentSize.width/2,contentSize.height/2);
this.addChild(map);
~~~
CCTMXTiledMap.tiledMap就是把圖片加載進來,getContentSize就是獲取地圖的大小,之所以把地圖的位置置為大小的一半,是因為地圖可能大于屏幕,這樣設置希望它一開始就能顯示左下部分。那如何獲得我們在地圖上設置的點呢,如下:
~~~
CCTMXObjectGroup zombiesGroup = map.objectGroupNamed("road");
ArrayList<HashMap<String, String>> zombies = zombiesGroup.objects;
// 分別以x和y為鍵,獲取坐標值信息---->封裝到點集合中
List<CGPoint> points = new ArrayList<CGPoint>();
for (HashMap<String, String> item : zombies) {
float x = Float.parseFloat(item.get("x"));
float y = Float.parseFloat(item.get("y"));
points.add(CGPoint.ccp(x, y));
}
~~~
這個可以說是固定格式,你可以把它寫到工具類中,最后points這個list中點信息的順序就是你在地圖上添加點的順序,所以添點忌隨意。有了點你就能干很多事,如設置移動路線。地圖加載講完后,就是音樂加載了。
這樣相對比較簡單,音樂的話要獲得一個音樂引擎來加載音樂。音樂引擎其實就是封裝了下mediaPlayer而已。看下代碼:
~~~
SoundEngine engine = SoundEngine.sharedEngine();
engine.preloadSound(getContext(), R.raw.start);
~~~
~~~
engine.playSound(getContext(), com.lxj.zhiwuvsani.R.raw.start, true);
~~~
如上,raw文件下放一些音樂文件,preloadSound是預先加載,可以把它放在游戲加載過程中,而playSound就是你想在哪播就設置在哪。true表示循環播放。
最后,說下字體的加載吧,Cocos2d_android字體用的是CCLabel,它繼承自CCSprite,設置如下:
~~~
CCLabel cLabel = CCLabel.makeLabel("hello world", "Roboto_Thin.ttf", 20);//創建字體,中間參數為ttf文件,20為字體大小
cLabel.setPosition(cgSize.width/2,cgSize.height/2);
this.addChild(cLabel,1);
~~~
它加載的字是hello world,加載的字體格式是Roboto_Thin.ttf,這個文件要存在assets文件夾下,如有不想設置那就直接置為“”。
講了這么多,現在己經可以自己布置場景,加載精靈任意擺放,并配上音樂字體了。一個游戲界面就差不多了,但是,很重要的一點,東西都不會動!!!!,不會動怎么玩。下一篇我將講講如何讓精靈動起來,設置各種action及判斷位置。看完下篇,你就能完整的做游戲了。當然看這些可能還不夠,這些只是最常用的,對于一些不常用的不懂的時還要去查下api,好啦,說了這么多,好累,歇會。
[植物大戰僵尸源碼下載](https://github.com/reallin/CoCos2d_android_PVZ)
- 前言
- Android底部tab與標題欄相結合
- Android免費獲取短信驗證碼
- android中Handler的源碼分析
- 詳解Fragment的傳值問題
- 詳談gson解析
- android新控件之toolbar,floatingActionButton,SnackBar,CollapsingToolbarLayout
- android自定義控件
- 淺談android的線程池
- Android的消息處理機制,AsyncTask源碼解析
- IPC——android進程間通信
- CoCos2d_android入門所需知道的一切
- Cocos2d_android你所需要知道的一切(下)
- Activity你需要知道的一切
- Activity啟動過程源碼分析
- Data Binding Guide——google官方文檔翻譯(上)
- Data Binding Guide——google官方文檔翻譯(下)
- android TextView實現跑馬燈效果
- android中生成excel
- Volley源碼解析
- LayoutInflater源碼解析
- android發送郵件
- android測試工具MonkeyRunner--google官網翻譯
- android View繪制源碼分析
- Android中Window添加View的底層原理
- 仿美團商品選購下拉菜單實現