做游戏是个很好玩的事情,由于兴趣我最近也在学习如何用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(下载链接)。它可以方便的进行地图标记,显示如下图:
如果你想改变背景图的样子,可以用上边栏的填充工具等进行绘制,如果想定点就新建一个对象层,如同图中的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,好啦,说了这么多,好累,歇会。
植物大战僵尸源码下载