zoukankan      html  css  js  c++  java
  • android:怎样用一天时间,写出“飞机大战”这种游戏!(无框架-SurfaceView绘制)

    序言
    作为一个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);

    未完待续。

    。。



  • 相关阅读:
    php && 逻辑与运算符使用说明
    php无穷递归算法
    PHP foreach 用法
    centos安装g++
    php 编译中apxs
    shutdown()
    C语言strtok()函数:字符串分割
    细谈select函数(C语言)
    setsockopt的作用
    STL之七:STL各种容器的使用时机详解
  • 原文地址:https://www.cnblogs.com/yxysuanfa/p/7119386.html
Copyright © 2011-2022 走看看