一、工程结构
--config
----Config
-----Constants
--object
-----Bird
-----Column
-----GameObject
-----Ground
--util
-----FileManager
-----SoundPlayer
--view
-----BaseView
-----LoadingView
-----MainView
MainActivity
二、代码
Config类
package com.hitsz.xiaokai.flybird.config; /** * Created by Administrator on 2016/3/26. */ public class Config { public final static int TO_MAIN_VIEW = 1;//命令切换到主视图 public final static int END_GAME = 0;//命令游戏结束 public final static int LOADING_GAME_INTERVAL = 2000;//加载界面时间 public final static int SPEED = (int) (Constants.SCREEN_WIDTH * 5 / 480);//column和ground的运动速度 public final static float COLUMN_Y_GAP = Constants.SCREEN_HEIGHT * 173 / 854;//column图片管子间空隙高度(不得修改,由图片决定) public final static float COLUMN_X_GAP = Constants.SCREEN_WIDTH / 2 + 50;//两个管子间的水平间距 public final static double v0 = Constants.SCREEN_HEIGHT * 23 / 854;//小鸟上抛初速度 public final static double g = Constants.SCREEN_HEIGHT * 3 / 854;//重力加速度 public final static double t = 0.6;//时间间隔 }Constants类
package com.hitsz.xiaokai.flybird.config; /** * Created by Administrator on 2016/3/26. */ public class Constants { public static float SCREEN_WIDTH;//屏幕宽度 public static float SCREEN_HEIGHT;//屏幕高度 }Bird类
package com.hitsz.xiaokai.flybird.object; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Rect; import com.hitsz.xiaokai.flybird.R; import com.hitsz.xiaokai.flybird.config.Config; import com.hitsz.xiaokai.flybird.config.Constants; /** * Created by Administrator on 2016/3/26. */ public class Bird extends GameObject { private Bitmap[] birdImgs; private Bitmap birdImg; private final double v0 = Config.v0; private final double g = Config.g; private final double t = Config.t; private double speed; private double s; private float angle; private float groundHeight; private Rect obj_rect; public Bird(Resources resources, float groundHeight) { super(resources); this.obj_rect = new Rect(); this.groundHeight = groundHeight; initBitmap(); } @Override public void step() { double v1 = speed; double v = v1 - g * t; speed = v; s= v1 * t - 0.5 * g * t * t; obj_y = obj_y - (float) s; if(obj_y <= 0) { obj_y = this.obj_height / 2; } if(obj_y >= Constants.SCREEN_HEIGHT - this.groundHeight - this.obj_height) { obj_y = Constants.SCREEN_HEIGHT - this.groundHeight - this.obj_height; } if(speed >= 0) { birdImg = birdImgs[(currentFrame / 3)]; currentFrame++; if(currentFrame == 9) { currentFrame = 0; } } else { birdImg = birdImgs[2]; } angle = (float) (s * 4); if(angle >= 30) { angle = 30; } if(angle <= -90) { angle = -90; } this.obj_mid_y = this.obj_y + this.obj_height / 2; //obj_rect.left = (int) obj_x; //obj_rect.top = (int) obj_y; //obj_rect.right = (int) (obj_x + obj_height + (obj_width - obj_height) * (1 - Math.cos(angle))); //obj_rect.bottom = (int) Math.floor (obj_y + obj_width - Math.abs((obj_width - obj_height) * Math.sin(angle))); obj_rect.left = (int) (obj_x + (obj_width - obj_height) / 2); obj_rect.top = (int) (obj_y + (obj_width - obj_height) / 2); obj_rect.right = (int) (obj_rect.left + obj_height); obj_rect.bottom = (int) (obj_rect.top + obj_height - (obj_width - obj_height) / 2); } public void flappy() { speed = v0; } @Override public void drawSelf(Canvas canvas) { canvas.save(); canvas.rotate(-angle, obj_mid_x, obj_mid_y); canvas.drawBitmap(birdImg, obj_x, obj_y, paint); canvas.restore(); /* paint.setColor(Color.BLACK); paint.setAlpha(50); canvas.drawRect(obj_rect, paint); */ } public boolean pass(Column column) { if(this.obj_mid_x <= column.getObjMidX() && column.getObjMidX() - this.obj_mid_x < 5) { return true; } return false; } public boolean hitColumn(Column column) { if(this.obj_rect.intersect(column.getObjRectTop()) || this.obj_rect.intersect(column.getObjRectBottom())) { return true; } return false; } public boolean hitGround(Ground ground) { /*if(this.obj_rect.intersect(ground.getObjRect())) { return true; } return false;*/ if((this.obj_rect.bottom + 1 ) >= ground.getObjRect().top) { return true; } return false; } @Override public void initBitmap() { birdImgs = new Bitmap[3]; birdImgs[0] = BitmapFactory.decodeResource(resources, R.drawable.bird0); birdImgs[1] = BitmapFactory.decodeResource(resources, R.drawable.bird1); birdImgs[2] = BitmapFactory.decodeResource(resources, R.drawable.bird2); birdImg = birdImgs[0]; this.obj_width = birdImg.getWidth(); this.obj_height = birdImg.getHeight(); this.obj_x = this.obj_width * 2; this.obj_y = Constants.SCREEN_HEIGHT / 2 - this.obj_height / 2; this.obj_mid_x = this.obj_x + this.obj_width / 2; this.obj_mid_y = this.obj_y + this.obj_height / 2; } @Override public void release() { for(int i=0; i<3; i++) { if(!birdImgs[i].isRecycled()) { birdImgs[i].recycle(); } } } public Rect getObjRect() { return this.obj_rect; } }Column类
package com.hitsz.xiaokai.flybird.object; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Rect; import com.hitsz.xiaokai.flybird.R; import com.hitsz.xiaokai.flybird.config.Config; import com.hitsz.xiaokai.flybird.config.Constants; import java.util.Random; /** * Created by Administrator on 2016/3/26. */ public class Column extends GameObject { private Bitmap columnImg; private Random random; private float groundHeight; private Rect rectTop; private Rect rectBottom; public Column(Resources resources, float x, float groundHeight) { super(resources); rectTop = new Rect(); rectBottom = new Rect(); this.groundHeight = groundHeight; random = new Random(); this.obj_mid_x = x; this.obj_mid_y = random.nextInt((int)(Constants.SCREEN_HEIGHT - this.groundHeight - Config.COLUMN_Y_GAP * 2)) + Config.COLUMN_Y_GAP; initBitmap(); } @Override public void step() { this.obj_mid_x -=Config.SPEED; if(this.obj_mid_x <= -(Config.COLUMN_X_GAP - this.obj_width / 2)) { this.obj_mid_x = Config.COLUMN_X_GAP * 2 + this.obj_width / 2; this.obj_mid_y = random.nextInt((int)(Constants.SCREEN_HEIGHT - this.groundHeight - Config.COLUMN_Y_GAP * 2)) + Config.COLUMN_Y_GAP; } } @Override public void drawSelf(Canvas canvas) { canvas.drawBitmap(columnImg, obj_mid_x - this.obj_width / 2, obj_mid_y - this.obj_height / 2, paint); } @Override public void initBitmap() { columnImg = BitmapFactory.decodeResource(resources, R.drawable.column); this.obj_width = columnImg.getWidth(); this.obj_height = columnImg.getHeight(); } @Override public void release() { if(!columnImg.isRecycled()) { columnImg.recycle(); } } public Rect getObjRectTop() { this.rectTop.set((int)(obj_mid_x - obj_width / 2), 0, (int)(obj_mid_x + obj_width / 2), (int)(obj_mid_y - Config.COLUMN_Y_GAP / 2)); return this.rectTop; } public Rect getObjRectBottom() { this.rectBottom.set((int)(obj_mid_x - obj_width / 2), (int)(obj_mid_y + Config.COLUMN_Y_GAP / 2), (int)(obj_mid_x + obj_width / 2), (int)Constants.SCREEN_HEIGHT); return this.rectBottom; } }GameObject类
package com.hitsz.xiaokai.flybird.object; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Paint; /** * Created by Administrator on 2016/3/26. */ public abstract class GameObject { protected int currentFrame;//当前动画帧 protected float obj_x;//对象左上角坐标 protected float obj_y; protected float obj_mid_x;//对象中心横坐标 protected float obj_mid_y;//对象中心纵坐标 protected float obj_width;//对象宽度 protected float obj_height;//对象高度 protected Resources resources; protected Paint paint; public GameObject(Resources resources) { this.resources = resources; paint = new Paint(); } //对象运动逻辑 public abstract void step(); //绘图方法 public abstract void drawSelf(Canvas canvas); //初始化如片资源 public abstract void initBitmap(); //释放图片资源 public abstract void release(); public void setObjX(float x) { this.obj_x = x; } public float getObjX() { return this.obj_x; } public void setObjY(float y) { this.obj_y = y; } public float getObjY() { return this.obj_y; } public void setObjMidX(float x) { this.obj_mid_x = x; } public float getObjMidX() { return this.obj_mid_x; } public void setObjMidY(float y) { this.obj_mid_y = y; } public float getObjMidY() { return this.obj_mid_y; } public void setObjWidth(float w) { this.obj_width = w; } public float getObjWidth() { return this.obj_width; } public void setObjHeight(float h) { this.obj_height = h; } public float getObjHeight() { return this.obj_height; } }Ground类
package com.hitsz.xiaokai.flybird.object; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Rect; import com.hitsz.xiaokai.flybird.R; import com.hitsz.xiaokai.flybird.config.Config; import com.hitsz.xiaokai.flybird.config.Constants; /** * Created by Administrator on 2016/3/26. */ public class Ground extends GameObject { private Bitmap groundImg; private Rect obj_rect; public Ground(Resources resources) { super(resources); this.obj_rect = new Rect(); this.obj_x = 0; initBitmap(); } @Override public void step() { this.obj_x -= Config.SPEED; if(this.obj_x <= -(this.obj_width - Constants.SCREEN_WIDTH)) { this.obj_x = -15; } } @Override public void drawSelf(Canvas canvas) { canvas.drawBitmap(groundImg, obj_x, obj_y, paint); } @Override public void initBitmap() { groundImg = BitmapFactory.decodeResource(resources, R.drawable.ground); this.obj_width = groundImg.getWidth(); this.obj_height = groundImg.getHeight(); this.obj_y = Constants.SCREEN_HEIGHT - this.obj_height; } public Rect getObjRect() { obj_rect.set(0, (int)obj_y, (int)Constants.SCREEN_WIDTH, (int)Constants.SCREEN_HEIGHT); return this.obj_rect; } @Override public void release() { if(!groundImg.isRecycled()) { groundImg.recycle(); } } }FileManager类
package com.hitsz.xiaokai.flybird.util; import android.os.Environment; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import org.apache.http.util.EncodingUtils; /** * Created by Administrator on 2016/3/26. */ public class FileManager { private File sdDir; private File dirPath; private File file; public String fileReader() { String score = null; try { FileInputStream fin = new FileInputStream(file); int length = fin.available(); byte[] buffer = new byte[length]; fin.read(buffer); score = EncodingUtils.getString(buffer, "UTF-8"); fin.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return score; } public void fileWriter(String msg) { String score = null; try { FileOutputStream fout = new FileOutputStream(file); byte[] buffer = msg.getBytes(); fout.write(buffer); fout.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void initFile() { String dirpath = getSDPath() + File.separator + "FlyBird"; dirPath = new File(dirpath); if(!dirPath.exists()) { dirPath.mkdirs(); } String filePath = dirpath + File.separator + "score.txt"; file = new File(filePath); if(!file.exists()) { try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } } public boolean sdIsAvalible() { return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); //判断sd卡是否存在 } public String getSDPath(){ sdDir = Environment.getExternalStorageDirectory();//获取跟目录 return sdDir.toString(); } }SoundPlayer类
package com.hitsz.xiaokai.flybird.util; import android.media.AudioManager; import android.media.SoundPool; import com.hitsz.xiaokai.flybird.MainActivity; import com.hitsz.xiaokai.flybird.R; import java.util.HashMap; /** * Created by Administrator on 2016/3/26. */ public class SoundPlayer { private SoundPool soundPool; private MainActivity mainActivity; private HashMap<Integer,Integer> map; public SoundPlayer(MainActivity mainActivity) { this.mainActivity=mainActivity; map=new HashMap<Integer,Integer>(); soundPool=new SoundPool(8, AudioManager.STREAM_MUSIC,0); } public void initSounds() { map.put(1, soundPool.load(mainActivity, R.raw.flappy, 1));//飞扬 map.put(2, soundPool.load(mainActivity, R.raw.pass, 1));//经过通到 map.put(3, soundPool.load(mainActivity, R.raw.hit, 1));//撞到 map.put(4, soundPool.load(mainActivity, R.raw.die, 1));//死掉 map.put(5, soundPool.load(mainActivity, R.raw.swooshing, 1));//切换 } public void playSound(int sound,int loop){ soundPool.play(sound,1,1,1,loop,1.0f); } }
package com.hitsz.xiaokai.flybird.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.view.SurfaceHolder; import android.view.SurfaceView; import com.hitsz.xiaokai.flybird.MainActivity; import com.hitsz.xiaokai.flybird.config.Constants; import com.hitsz.xiaokai.flybird.util.SoundPlayer; /** * Created by Administrator on 2016/3/26. */ public class BaseView extends SurfaceView implements SurfaceHolder.Callback, Runnable { protected float scaleX;//背景图片缩放比例 protected float scaleY; protected MainActivity mainActivity; protected SoundPlayer soundPlayer; protected Canvas canvas;//画布对象 protected Paint paint;//画笔对象 protected SurfaceHolder sfh; protected Thread thread;//绘画线程 protected boolean threadFlag;//标记线程运行 //构造函数 public BaseView(Context context, SoundPlayer soundPlayer) { super(context); this.mainActivity = (MainActivity) context; this.soundPlayer = soundPlayer; this.sfh = this.getHolder(); this.sfh.addCallback(this); this.paint = new Paint(); } //线程运行的方法 @Override public void run() {} //初始化图片资源 public void initBitmap() {} //释放图片资源 public void release() {} //绘图方法 public void drawSelf() {} //视图改变的方法 @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {} //视图创建的方法 @Override public void surfaceCreated(SurfaceHolder arg0) { Constants.SCREEN_WIDTH = this.getWidth(); Constants.SCREEN_HEIGHT = this.getHeight(); this.threadFlag = true; } //视图销毁的方法 @Override public void surfaceDestroyed(SurfaceHolder arg0) { this.threadFlag = false; } public void setThreadFlag(boolean threadFlag) { this.threadFlag = threadFlag; } }
package com.hitsz.xiaokai.flybird.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Rect; import android.view.SurfaceHolder; import com.hitsz.xiaokai.flybird.R; import com.hitsz.xiaokai.flybird.config.Config; import com.hitsz.xiaokai.flybird.config.Constants; import com.hitsz.xiaokai.flybird.util.SoundPlayer; /** * Created by Administrator on 2016/3/26. */ public class LoadingView extends BaseView { private Bitmap bgImg; private Bitmap logoImg; private Bitmap textImg; //private float bgImgX;//图片坐标 //private float bgImgY; private float logoImgX; private float logoImgY; private float textImgX; private float textImgY; private String author = "仿写者:小开";//绘制文字区域 private Rect rect; private float strWidth; private float strHeight; private float textX; private float textY; public LoadingView(Context context, SoundPlayer soundPlayer) { super(context, soundPlayer); rect = new Rect(); this.thread = new Thread(this); } @Override public void surfaceCreated(SurfaceHolder arg0) { super.surfaceCreated(arg0); initBitmap(); if(this.thread.isAlive()) { this.thread.start(); } else { this.thread = new Thread(this); this.thread.start(); } } @Override public void initBitmap() { this.bgImg = BitmapFactory.decodeResource(getResources(), R.drawable.bg); this.logoImg = BitmapFactory.decodeResource(getResources(), R.drawable.logo); this.textImg = BitmapFactory.decodeResource(getResources(), R.drawable.text_logo); this.scaleX = Constants.SCREEN_WIDTH / this.bgImg.getWidth(); this.scaleY = Constants.SCREEN_HEIGHT / this.bgImg.getHeight(); this.textImgX = (Constants.SCREEN_WIDTH - this.textImg.getWidth()) / 2; this.textImgY = Constants.SCREEN_HEIGHT / 2 - this.textImg.getHeight() * 2; this.logoImgX = (Constants.SCREEN_WIDTH - this.logoImg.getWidth()) / 2; this.logoImgY = Constants.SCREEN_HEIGHT / 2 - this.logoImg.getWidth() * 0; this.paint.setTextSize(40); this.paint.getTextBounds(author, 0, author.length(), rect); this.strWidth = rect.width(); this.strHeight = rect.height(); this.textX = Constants.SCREEN_WIDTH / 2 - this.strWidth / 2; this.textY = Constants.SCREEN_HEIGHT / 2 + logoImg.getHeight() + this.strHeight * 2; } @Override public void run() { while(this.threadFlag) { drawSelf(); try { Thread.sleep(Config.LOADING_GAME_INTERVAL); } catch (InterruptedException e) { e.printStackTrace(); } this.threadFlag = false; } mainActivity.getHandler().sendEmptyMessage(Config.TO_MAIN_VIEW); } @Override public void drawSelf() { try { canvas = sfh.lockCanvas(); canvas.save(); canvas.scale(this.scaleX, this.scaleY); canvas.drawBitmap(bgImg, 0, 0, paint); canvas.restore(); canvas.drawBitmap(textImg, textImgX, textImgY, paint); canvas.drawBitmap(logoImg, logoImgX, logoImgY, paint); canvas.drawText(author, textX, textY, paint); } catch(Exception err) { err.printStackTrace(); } finally { if(canvas != null) { sfh.unlockCanvasAndPost(canvas); } } } @Override public void surfaceDestroyed(SurfaceHolder arg0) { super.surfaceDestroyed(arg0); release(); } @Override public void release() { if(!this.bgImg.isRecycled()){ this.bgImg.recycle(); } if(!this.logoImg.isRecycled()){ this.logoImg.recycle(); } if(!this.textImg.isRecycled()){ this.textImg.recycle(); } } }
package com.hitsz.xiaokai.flybird.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.widget.Toast; import com.hitsz.xiaokai.flybird.R; import com.hitsz.xiaokai.flybird.config.Config; import com.hitsz.xiaokai.flybird.config.Constants; import com.hitsz.xiaokai.flybird.object.Bird; import com.hitsz.xiaokai.flybird.object.Column; import com.hitsz.xiaokai.flybird.object.Ground; import com.hitsz.xiaokai.flybird.util.FileManager; import com.hitsz.xiaokai.flybird.util.SoundPlayer; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2016/3/26. */ public class MainView extends BaseView { private Ground ground; private Column column1; private Column column2; private Column column3; private Bird bird; private FileManager fileManager; private Bitmap bgImg; private Bitmap startImg; private Bitmap endImg; private Bitmap restartButtonImg; private Bitmap exitButtonImg; private Bitmap noticeImg; private Bitmap pauseButtonImg; private Bitmap bigNumbersImg; private Bitmap smallNumbersImg; private Bitmap medalImg; private float startImgX; private float startImgY; private float endImgX; private float endImgY; private float noticeImgX; private float noticeImgY; private float restartButtonImgX; private float restartButtonImgY; private float exitButtonImgX; private float exitButtonImgY; private float pauseButtonImgX; private float pauseButtonImgY; private float bigNumbersImgX; private float bigNumbersImgY; private float smallNumbersImgX;//bestScore位置 private float smallNumbersImgY; private float smallScoreX; private float smallScoreY; private float medalImgX; private float medalImgY; private boolean isStart; private boolean isHit; private boolean isOver; private boolean isPause; private boolean isWrite; private int score; private int bestScore; //private Rect rect; public MainView(Context context, SoundPlayer soundPlayer) { super(context, soundPlayer); isStart = false; isHit = false; isOver = false; isPause = false; isWrite = false; //rect = new Rect(); //Toast.makeText(this.mainActivity.getApplicationContext(), Constants.SCREEN_WIDTH + " " + Constants.SCREEN_HEIGHT, Toast.LENGTH_LONG).show(); fileManager = new FileManager(); if(fileManager.sdIsAvalible()) { fileManager.initFile(); if(fileManager.fileReader().length() <= 0) { bestScore = 0; } else { bestScore = Integer.parseInt(fileManager.fileReader()); } } else { //Looper.prepare(); Toast.makeText(this.mainActivity.getApplicationContext(), "SD卡不可用,将无法保存您的最高纪录", Toast.LENGTH_LONG).show(); //Looper.loop(); } ground = new Ground(getResources()); column1 = new Column(getResources(), Config.COLUMN_X_GAP * 2, ground.getObjHeight()); column2 = new Column(getResources(), Config.COLUMN_X_GAP + column1.getObjMidX(), ground.getObjHeight()); column3 = new Column(getResources(), Config.COLUMN_X_GAP + column2.getObjMidX(), ground.getObjHeight()); bird = new Bird(getResources(), ground.getObjHeight()); this.thread = new Thread(this); } @Override public void run() { while(this.threadFlag) { if(!isHit && !isOver) { ground.step(); } if(isStart && !isHit &&!isOver) { column1.step(); column2.step(); column3.step(); } if(isStart) { bird.step(); } drawSelf(); if(isOver) { threadFlag = false; } if(isPause) { synchronized (thread) { try { thread.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } try { Thread.sleep(1000 / 60); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } drawSelf(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } drawNotice(); if(fileManager.sdIsAvalible()) { if(score > bestScore) { fileManager.fileWriter(String.valueOf(score)); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } for(int i=0; i<=score; i++) { drawResult(i); try { Thread.sleep(1000/60); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(thread) { drawMedal(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } drawButton(); isWrite = true; } @Override public void drawSelf() { try { canvas = sfh.lockCanvas(); drawObject(); if(!isHit) { if(bird.pass(column1) || bird.pass(column2) || bird.pass(column3)) { soundPlayer.playSound(2, 0); score++; } if(bird.hitColumn(column1) || bird.hitColumn(column2) ||bird.hitColumn(column3)){ soundPlayer.playSound(3, 0); paint.setAlpha(50); paint.setColor(Color.WHITE); canvas.drawRect(0, 0, Constants.SCREEN_WIDTH, Constants.SCREEN_HEIGHT, paint); isHit = true; } } /*paint.setTextSize(26); paint.setColor(Color.WHITE); paint.getTextBounds(String.valueOf(score), 0, String.valueOf(score).length(), rect); canvas.drawText(String.valueOf(score), 10, rect.height() + 5, paint); */ if(!isOver) { drawScore(bigNumbersImg, bigNumbersImgX, bigNumbersImgY, score); } if(isOver) { soundPlayer.playSound(5, 0); canvas.drawBitmap(endImg, endImgX, endImgY, paint); } if(!isOver) { if(bird.hitGround(ground)){ soundPlayer.playSound(4, 0); isOver = true; } } if(!isStart) { if(!isStart) { canvas.drawBitmap(startImg, startImgX, startImgY, paint); } } if(isStart && !isHit && !isOver) { if(!isPause) { canvas.save(); canvas.clipRect(pauseButtonImgX, pauseButtonImgY, pauseButtonImgX + pauseButtonImg.getWidth(), pauseButtonImgY + pauseButtonImg.getHeight() / 2); canvas.drawBitmap(pauseButtonImg, pauseButtonImgX, pauseButtonImgY, paint); canvas.restore(); } else { canvas.save(); canvas.clipRect(pauseButtonImgX, pauseButtonImgY, pauseButtonImgX + pauseButtonImg.getWidth(), pauseButtonImgY + pauseButtonImg.getHeight() / 2); canvas.drawBitmap(pauseButtonImg, pauseButtonImgX, pauseButtonImgY - pauseButtonImg.getHeight() / 2, paint); canvas.restore(); } } } catch (Exception err) { err.printStackTrace(); } finally { if(canvas != null) { sfh.unlockCanvasAndPost(canvas); } } } public void drawNotice() { try { canvas = sfh.lockCanvas(); drawObject(); soundPlayer.playSound(5, 0); canvas.drawBitmap(endImg, endImgX, endImgY, paint); canvas.drawBitmap(noticeImg, noticeImgX, noticeImgY, paint); } catch (Exception err) { err.printStackTrace(); } finally { if(canvas != null) { sfh.unlockCanvasAndPost(canvas); } } } public void drawResult(int i) { try { canvas = sfh.lockCanvas(); drawObject(); //soundPlayer.playSound(5, 0); canvas.drawBitmap(endImg, endImgX, endImgY, paint); canvas.drawBitmap(noticeImg, noticeImgX, noticeImgY, paint); /* paint.setTextSize(26); paint.setColor(Color.WHITE); paint.getTextBounds(String.valueOf(bestScore), 0, String.valueOf(bestScore).length(), rect); canvas.drawText(String.valueOf(bestScore), noticeImgX + noticeImg.getWidth() - rect.width(), noticeImgY + noticeImg.getHeight() - rect.height(), paint); */ drawScore(smallNumbersImg, smallScoreX, smallScoreY, i); //drawScore(smallNumbersImg, smallNumbersImgX, smallNumbersImgY, bestScore); } catch (Exception err) { err.printStackTrace(); } finally { if(canvas != null) { sfh.unlockCanvasAndPost(canvas); } } } public void drawMedal() { try { canvas = sfh.lockCanvas(); drawObject(); soundPlayer.playSound(5, 0); canvas.drawBitmap(endImg, endImgX, endImgY, paint); canvas.drawBitmap(noticeImg, noticeImgX, noticeImgY, paint); /* paint.setTextSize(26); paint.setColor(Color.WHITE); paint.getTextBounds(String.valueOf(bestScore), 0, String.valueOf(bestScore).length(), rect); canvas.drawText(String.valueOf(bestScore), noticeImgX + noticeImg.getWidth() - rect.width(), noticeImgY + noticeImg.getHeight() - rect.height(), paint); */ drawScore(smallNumbersImg, smallScoreX, smallScoreY, score); drawScore(smallNumbersImg, smallNumbersImgX, smallNumbersImgY, bestScore); drawMedalImg(); } catch (Exception err) { err.printStackTrace(); } finally { if(canvas != null) { sfh.unlockCanvasAndPost(canvas); } } } public void drawButton() { try { canvas = sfh.lockCanvas(); drawObject(); soundPlayer.playSound(5, 0); canvas.drawBitmap(endImg, endImgX, endImgY, paint); canvas.drawBitmap(noticeImg, noticeImgX, noticeImgY, paint); drawScore(smallNumbersImg, smallScoreX, smallScoreY, score); drawScore(smallNumbersImg, smallNumbersImgX, smallNumbersImgY, bestScore); drawMedalImg(); canvas.drawBitmap(restartButtonImg, restartButtonImgX, restartButtonImgY, paint); canvas.drawBitmap(exitButtonImg, exitButtonImgX, exitButtonImgY, paint); } catch (Exception err) { err.printStackTrace(); } finally { if(canvas != null) { sfh.unlockCanvasAndPost(canvas); } } } public void drawObject() { canvas.save(); canvas.scale(scaleX, scaleY); canvas.drawBitmap(bgImg, 0, 0, paint); canvas.restore(); column1.drawSelf(canvas); column2.drawSelf(canvas); column3.drawSelf(canvas); bird.drawSelf(canvas); ground.drawSelf(canvas); } public void drawMedalImg() { canvas.save(); canvas.clipRect(medalImgX, medalImgY, medalImgX + medalImg.getWidth(), medalImgY + medalImg.getHeight() / 2); if(score >= 60) { canvas.drawBitmap(medalImg, medalImgX, medalImgY - medalImg.getHeight() / 2, paint); } else { canvas.drawBitmap(medalImg, medalImgX, medalImgY, paint); } canvas.restore(); } public void drawScore(Bitmap numbersImg, float x, float y, int num) { List<Integer> list = new ArrayList<Integer>(); int scoreCopy = num; int quotient = 0; while((quotient = scoreCopy / 10) != 0) { list.add(scoreCopy % 10); scoreCopy = quotient; } list.add(scoreCopy % 10); float posX = x; float posY = y; int len = list.size(); float oddNumW = numbersImg.getWidth() / 10; float oddNumH = numbersImg.getHeight(); posX -= len * oddNumW / 2; canvas.save(); for(int i=len-1; i>=0; i--) { switch(list.get(i)) { case 0: canvas.clipRect(posX, posY, posX + oddNumW, posY + oddNumH); canvas.drawBitmap(numbersImg, posX - 0 * oddNumW, posY, paint); posX += oddNumW; canvas.restore(); canvas.save(); break; case 1: canvas.clipRect(posX, posY, posX + oddNumW, posY + oddNumH); canvas.drawBitmap(numbersImg, posX - 1 * oddNumW, posY, paint); posX += oddNumW; canvas.restore(); canvas.save(); break; case 2: canvas.clipRect(posX, posY, posX + oddNumW, posY + oddNumH); canvas.drawBitmap(numbersImg, posX - 2 * oddNumW, posY, paint); posX += oddNumW; canvas.restore(); canvas.save(); break; case 3: canvas.clipRect(posX, posY, posX + oddNumW, posY + oddNumH); canvas.drawBitmap(numbersImg, posX - 3 * oddNumW, posY, paint); posX += oddNumW; canvas.restore(); canvas.save(); break; case 4: canvas.clipRect(posX, posY, posX + oddNumW, posY + oddNumH); canvas.drawBitmap(numbersImg, posX - 4 * oddNumW, posY, paint); posX += oddNumW; canvas.restore(); canvas.save(); break; case 5: canvas.clipRect(posX, posY, posX + oddNumW, posY + oddNumH); canvas.drawBitmap(numbersImg, posX - 5 * oddNumW, posY, paint); posX += oddNumW; canvas.restore(); canvas.save(); break; case 6: canvas.clipRect(posX, posY, posX + oddNumW, posY + oddNumH); canvas.drawBitmap(numbersImg, posX - 6 * oddNumW, posY, paint); posX += oddNumW; canvas.restore(); canvas.save(); break; case 7: canvas.clipRect(posX, posY, posX + oddNumW, posY + oddNumH); canvas.drawBitmap(numbersImg, posX - 7 * oddNumW, posY, paint); posX += oddNumW; canvas.restore(); canvas.save(); break; case 8: canvas.clipRect(posX, posY, posX + oddNumW, posY + oddNumH); canvas.drawBitmap(numbersImg, posX - 8 * oddNumW, posY, paint); posX += oddNumW; canvas.restore(); canvas.save(); break; case 9: canvas.clipRect(posX, posY, posX + oddNumW, posY + oddNumH); canvas.drawBitmap(numbersImg, posX - 9 * oddNumW, posY, paint); posX += oddNumW; canvas.restore(); canvas.save(); break; } } canvas.restore(); } // 响应触屏事件的方法 @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN && event.getPointerCount() == 1) { float x = event.getX(); float y = event.getY(); if(isWrite) { if(x >= restartButtonImgX && x <= restartButtonImgX + restartButtonImg.getWidth() && y >= restartButtonImgY && y <= restartButtonImgY + restartButtonImg.getHeight()) { mainActivity.getHandler().sendEmptyMessage(Config.TO_MAIN_VIEW); } if(x >= exitButtonImgX && x <= exitButtonImgX + exitButtonImg.getWidth() && y >= exitButtonImgY && y <= exitButtonImgY + exitButtonImg.getHeight()) { mainActivity.getHandler().sendEmptyMessage(Config.END_GAME); } } if(!isStart) { isStart = true; } if(!isHit && !isOver) { if(x <= pauseButtonImgX || x>= pauseButtonImgX + pauseButtonImg.getWidth() || y <= pauseButtonImgY || y>= pauseButtonImgY + pauseButtonImg.getHeight() / 2) { bird.flappy(); soundPlayer.playSound(1, 0); } } if(isStart && !isHit && !isOver) { if(x >= pauseButtonImgX && x<= pauseButtonImgX + pauseButtonImg.getWidth() && y >= pauseButtonImgY && y<= pauseButtonImgY + pauseButtonImg.getHeight() / 2) { isPause = !isPause; if(isPause == false) { synchronized(this.thread) { thread.notify(); } } } } return true; } return false; } @Override public void surfaceCreated(SurfaceHolder arg0) { super.surfaceCreated(arg0); initBitmap(); if(this.thread.isAlive()) { this.thread.start(); } else { this.thread = new Thread(this); this.thread.start(); } } @Override public void initBitmap() { bgImg = BitmapFactory.decodeResource(getResources(), R.drawable.bg); startImg = BitmapFactory.decodeResource(getResources(), R.drawable.start); endImg = BitmapFactory.decodeResource(getResources(), R.drawable.text_gameover); restartButtonImg = BitmapFactory.decodeResource(getResources(), R.drawable.restartbutton); exitButtonImg = BitmapFactory.decodeResource(getResources(), R.drawable.exitbutton); noticeImg = BitmapFactory.decodeResource(getResources(), R.drawable.notice); pauseButtonImg = BitmapFactory.decodeResource(getResources(), R.drawable.pausebutton); bigNumbersImg = BitmapFactory.decodeResource(getResources(), R.drawable.bignumbers); smallNumbersImg = BitmapFactory.decodeResource(getResources(), R.drawable.smallnumbers); medalImg = BitmapFactory.decodeResource(getResources(), R.drawable.medal); this.scaleX = Constants.SCREEN_WIDTH / bgImg.getWidth(); this.scaleY = Constants.SCREEN_HEIGHT / bgImg.getHeight(); startImgX = Constants.SCREEN_WIDTH / 2 - startImg.getWidth() / 2; startImgY = Constants.SCREEN_HEIGHT / 2 - startImg.getHeight() / 2; endImgX = Constants.SCREEN_WIDTH / 2 - endImg.getWidth() / 2; endImgY = Constants.SCREEN_HEIGHT / 2 - endImg.getHeight() * 3; noticeImgX = Constants.SCREEN_WIDTH / 2 - noticeImg.getWidth() / 2; noticeImgY = Constants.SCREEN_HEIGHT / 2 - endImg.getHeight(); restartButtonImgX = Constants.SCREEN_WIDTH / 2 - restartButtonImg.getWidth() * 5 / 4; restartButtonImgY = Constants.SCREEN_HEIGHT / 2 + noticeImg.getHeight(); exitButtonImgX = Constants.SCREEN_WIDTH / 2 + exitButtonImg.getWidth() / 4; exitButtonImgY = Constants.SCREEN_HEIGHT / 2 + noticeImg.getHeight(); pauseButtonImgX = 0; pauseButtonImgY = Constants.SCREEN_HEIGHT - pauseButtonImg.getHeight() / 2; bigNumbersImgX = Constants.SCREEN_WIDTH / 2; bigNumbersImgY = 10; smallNumbersImgX = noticeImgX + noticeImg.getWidth() * 5 / 6; smallNumbersImgY =noticeImgY + noticeImg.getHeight() - smallNumbersImg.getHeight() * 2; smallScoreX = smallNumbersImgX; smallScoreY = smallNumbersImgY - smallNumbersImg.getHeight() * 23 / 10; medalImgX = noticeImgX + noticeImg.getWidth() / 8; medalImgY = noticeImgY + noticeImg.getHeight() * 7 / 20; } @Override public void surfaceDestroyed(SurfaceHolder arg0) { super.surfaceDestroyed(arg0); release(); } @Override public void release() { if(!bgImg.isRecycled()) { bgImg.recycle(); } if(!startImg.isRecycled()) { startImg.recycle(); } if(!endImg.isRecycled()) { endImg.recycle(); } if(!restartButtonImg.isRecycled()) { restartButtonImg.recycle(); } if(!exitButtonImg.isRecycled()) { exitButtonImg.recycle(); } if(!noticeImg.isRecycled()) { noticeImg.recycle(); } if(!pauseButtonImg.isRecycled()) { pauseButtonImg.recycle(); } if(!bigNumbersImg .isRecycled()) { bigNumbersImg .recycle(); } if(!smallNumbersImg .isRecycled()) { smallNumbersImg .recycle(); } if(!medalImg.isRecycled()) { medalImg.recycle(); } ground.release(); column1.release(); column2.release(); column3.release(); bird.release(); } }
package com.hitsz.xiaokai.flybird; import android.app.Activity; import android.os.Handler; import android.os.Message; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; import com.hitsz.xiaokai.flybird.config.Config; import com.hitsz.xiaokai.flybird.util.SoundPlayer; import com.hitsz.xiaokai.flybird.view.LoadingView; import com.hitsz.xiaokai.flybird.view.MainView; public class MainActivity extends Activity { private LoadingView loadingView;//游戏载入窗口 private MainView mainView;//游戏主窗口 private SoundPlayer soundPlayer;//音乐播放器 private Handler handler = new Handler() { public void handleMessage(Message msg) { if(msg.what == Config.TO_MAIN_VIEW) { toMainView(); } if(msg.what == Config.END_GAME) { endGame(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); this.soundPlayer = new SoundPlayer(this); this.soundPlayer.initSounds(); this.loadingView = new LoadingView(this, soundPlayer); this.setContentView(loadingView); } public void toMainView() { if(this.mainView == null) { this.mainView = new MainView(this, soundPlayer); } else { this.mainView = null; this.mainView = new MainView(this, soundPlayer); } this.setContentView(this.mainView); this.loadingView = null; } public void endGame() { if(this.mainView != null) { this.mainView.setThreadFlag(false); } if(this.loadingView != null) { this.loadingView.setThreadFlag(false); } this.finish(); } public Handler getHandler() { return this.handler; } }
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
github:点击打开链接(https://github.com/stephenxe/flybird)
启动界面
启动界面2
结束界面