研读FlappyBird代码

一、工程结构

--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);
    }
}

BaseView类

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;
    }


}

LoadingView类

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();
        }
    }

}

MainView类

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();
    }

}

MainActivity类

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;
    }
}

AndroidManife文件添加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

三、工程文件

github:点击打开链接(https://github.com/stephenxe/flybird)

启动界面

启动界面2

结束界面



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值