android:怎样用一天时间,写出“飞机大战”这种游戏!(无框架-SurfaceView绘制)
序言
作为一个android开发人员,时常想开发一个小游戏娱乐一下大家,今天就说说,我是怎么样一天写出一个简单的“飞机大战”的.
1.玩家飞机
2.敌方飞机
3.玩家飞机发送的子弹
4.敌方Boss飞机发送的子弹
我们须要控制的有:
1.绘制屏幕内的角色
2.控制角色的逻辑。比方:敌方飞机与我方飞机的碰撞检測,我方飞机发射的子弹与敌方飞机之间的碰撞检測,敌方Boss飞机发射的子弹与我方飞机直接的碰撞检測等等。
资源:
要完毕一个游戏,还要有资源的载入。比方飞机,子弹等图片的载入等,音效的载入。
游戏背景的绘制
事实上是一张图,这张图能够首尾相接。也即是“卷轴”,原理就是卡马克卷轴算法的原理。
以下分析代码区:
对于背景的绘制。事实上是循环绘制一张图:本游戏的绘制逻辑:
然后,我们仅仅须要在一个布局上,将PlaneView加入进去就可以:
未完待续。
作为一个android开发人员,时常想开发一个小游戏娱乐一下大家,今天就说说,我是怎么样一天写出一个简单的“飞机大战”的.
体验地址:http://www.wandoujia.com/apps/edu.njupt.zhb.planegame
源码:https://github.com/nuptboyzhb/newplanegame
游戏分析
玩过“飞机大战”游戏的都知道,飞机大战中的主要“角色”有:1.玩家飞机
2.敌方飞机
3.玩家飞机发送的子弹
4.敌方Boss飞机发送的子弹
我们须要控制的有:
1.绘制屏幕内的角色
2.控制角色的逻辑。比方:敌方飞机与我方飞机的碰撞检測,我方飞机发射的子弹与敌方飞机之间的碰撞检測,敌方Boss飞机发射的子弹与我方飞机直接的碰撞检測等等。
资源:
要完毕一个游戏,还要有资源的载入。比方飞机,子弹等图片的载入等,音效的载入。
游戏背景的绘制
事实上是一张图,这张图能够首尾相接。也即是“卷轴”,原理就是卡马克卷轴算法的原理。
以下分析代码区:
事实上,抛开android平台,不论什么一个平台,做这样一个游戏。都须要这些逻辑。针对android平台。我们看一下,SurfaceView的绘制框架。
直接贴代码:
package edu.njupt.zhb.game.view; /** * * @author Zheng Haibo * @webset: http://www.mobctrl.net * @android开发联盟QQ群:272209595 */ public class PlaneView extends SurfaceView implements Callback, Runnable { private SurfaceHolder surfaceHolder; private long sleep_time = 16;//绘制周期 private int screenHeight; private int screenWidth; private Thread thread; private Canvas canvas; private Paint paint; private GameScreen currentScreen; private int level = 0; private int backgroundSpeed = 1; public PlaneView(Context context) { super(context); System.out.println("debug:PlaneView()"); surfaceHolder = this.getHolder(); surfaceHolder.addCallback(this); surfaceHolder.setFormat(PixelFormat.TRANSLUCENT); paint = new Paint(); paint.setAntiAlias(true); paint.setDither(true); } @Override public void surfaceCreated(SurfaceHolder holder) { System.out.println("debug:surfaceCreated"); setZOrderOnTop(false); isGameOver = false; if (isPause) { return; } screenHeight = this.getHeight(); screenWidth = this.getWidth(); initPlane(); thread = new Thread(this); thread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { System.out.println("debug:surfaceChanged"); } @Override public void surfaceDestroyed(SurfaceHolder holder) { System.out.println("debug:surfaceDestroyed"); if (lift > 0) { planeViewCallback.onGamePause(); } isPause = true; } @Override public void run() { while (!isGameOver) {//控制绘制周期 if (isPause) { try { Thread.sleep(sleep_time); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } continue; } long starttime = System.currentTimeMillis(); drawScreen(); long time = System.currentTimeMillis() - starttime; if (time < sleep_time) { try { Thread.sleep(sleep_time - time); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 绘制场景 */ private void drawScreen() { canvas = surfaceHolder.lockCanvas(); if (null == canvas) { return; } //清除 canvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR); paint.setAlpha(255); gameLogic(); gameDraw(); if (null != canvas) { surfaceHolder.unlockCanvasAndPost(canvas); } } /** * 游戏逻辑 */ private void gameLogic() { //TO DO 控制游戏逻辑 ... } private void gameDraw() { //先绘制游戏背景 drawBackground(backgroundSpeed * frameSeq); if (currentScreen == GameScreen.NORMAL) { synchronized (planes) { drawPlanes(); drawBullets(); drawMasterPlane(); } } else if (currentScreen == GameScreen.BOSS) { drawBullets(); drawBossPlane(); drawBossBullets(); drawMasterPlane(); } } private void drawBossPlane() { if (null != bossPlane) { if (bossPlane.isClicked()) {// draw blast img bossPlane.onBlastDraw(canvas, paint); if (bossPlane.isBlastFrameEnd()) { bossPlane.setClicked(false); } } bossPlane.onDraw(canvas, paint); } } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); System.out.println("debug:onDraw"); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); System.out.println("debug:onDetachedFromWindow..."); isPause = false; isGameOver = true; //释放资源 for (PlaneRes plane : planesRes) { plane.getBitmap().recycle(); } for (BulletRes bulletRes : bulletsRes) { bulletRes.getBitmap().recycle(); } } /** * 用户交互 */ @Override public boolean onTouchEvent(MotionEvent e) { int x = (int) e.getX(); int y = (int) e.getY(); switch (e.getAction()) { case MotionEvent.ACTION_DOWN: if (masterPlane.isContainPoint(x, y)) { isMove = true; } break; case MotionEvent.ACTION_MOVE: if (isMove) { synchronized (masterPlane) { masterPlane.updatePosition(x, y);//控制玩家飞机的移动 } } break; case MotionEvent.ACTION_UP: isMove = false; break; } return true; } }
对于背景的绘制。事实上是循环绘制一张图:本游戏的绘制逻辑:
private void drawBackground(int yOffset) { yOffset %= screenHeight; if (yOffset == 0) { canvas.drawBitmap(backgroundBmp, 0, 0, paint); } else { canvas.drawBitmap(backgroundBmp, new Rect(0, screenHeight - yOffset, screenWidth, screenHeight), new Rect(0, 0, screenWidth, yOffset + 1), paint); canvas.drawBitmap(backgroundBmp, new Rect(0, 0, screenWidth, screenHeight - yOffset), new Rect(0, yOffset, screenWidth, screenHeight), paint); } }
然后,我们仅仅须要在一个布局上,将PlaneView加入进去就可以:
如:
planeView = new PlaneView(this); planeView.setPlaneViewCallback(this); planeView.setGameOverCallback(this); planeView.isMediaOpen = this.isMediaOpen; LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); rl_plane.addView(planeView, lp);
未完待续。
。。
。
。