做游戏是个很好玩的事情,由于兴趣我最近也在学习如何用android做游戏。顺便它选择了植物大战僵尸来当我的嵌入式作业 。熬了两天两夜终于把它完成了。这个过程从学习调研到写代码的各种心塞到完工,花了很多时间,也花了很多精力,但觉得是值得的。本文并不是讲解植物大战僵尸是怎么做的,而是讲解CoCos2d_android常用的基础知识,当然只要知道这些知识也就能够能完成这个游戏,最后会把代码贴出。先看下效果图:
![](https://box.kancloud.cn/2016-04-08_570771b573e53.jpg)
![](https://box.kancloud.cn/2016-04-08_570771b5a5865.jpg)
、
### 一.Cocos2d_android介绍
Cocos2d是一个大家庭,包括Cocos2d-iphone,Cocos2d-x,Cocos2d-javascript等。而在国内,Cocos2d-x则相对领先。在中国的2D手机游戏开发中,Cocos2d-x引擎的份额超过70%。不同家庭成员之间只是语言不同,而实现的接口名称都相同。所以只要学习一个,其它的就都比较好理解了。本文讲的是Coscos2d_android,因为它是用java实现的,所以对我来说学起来比较快。
### 二.Cocos2d_android架构
![](https://box.kancloud.cn/2016-04-08_570771b5cc5a1.jpg)
如上图,Cocos2d这游戏引擎主要由图形引擎(Graphic),声音引擎(Audio),物理引擎(Box2d),脚本库以及相关语言等组成。我们重点关注开发过程中需要注意的。先看一张Cocos2d_android的代码结构图:
![](https://box.kancloud.cn/2016-04-08_570771b5ec7d2.jpg)
对于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))。它可以方便的进行地图标记,显示如下图:
![](https://box.kancloud.cn/2016-04-08_570771b60d26c.jpg)
如果你想改变背景图的样子,可以用上边栏的填充工具等进行绘制,如果想定点就新建一个对象层,如同图中的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的底层原理
- 仿美团商品选购下拉菜单实现