android:如何用一天時間,寫出“飛機大戰”這樣的遊戲!(無框架-SurfaceView繪製)
阿新 • • 發佈:2019-02-12
序言
作為一個android開發者,時常想開發一個小遊戲娛樂一下大家,今天就說說,我是怎麼樣一天寫出一個簡單的“飛機大戰”的.
1.玩家飛機
2.敵方飛機
3.玩家飛機發送的子彈
4.敵方Boss飛機發送的子彈
我們需要控制的有:
1.繪製螢幕內的角色
2.控制角色的邏輯,比如:敵方飛機與我方飛機的碰撞檢測,我方飛機發射的子彈與敵方飛機之間的碰撞檢測,敵方Boss飛機發射的子彈與我方飛機直接的碰撞檢測等等。
資源:
要完成一個遊戲,還要有資源的載入,比如飛機,子彈等圖片的載入等,音效的載入。
遊戲背景的繪製
其實是一張圖,這張圖可以首尾相接,也即是“卷軸”,原理就是卡馬克卷軸演算法的原理。
下面分析程式碼區 :
對於背景的繪製,其實是迴圈繪製一張圖:本遊戲的繪製邏輯:
然後,我們只需要在一個佈局上,將PlaneView新增進去即可:
未完待續。。。。。
作為一個android開發者,時常想開發一個小遊戲娛樂一下大家,今天就說說,我是怎麼樣一天寫出一個簡單的“飛機大戰”的.
遊戲分析
玩過“飛機大戰”遊戲的都知道,飛機大戰中的主要“角色”有: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);
未完待續。。。。。