Android 模仿flabby bird游戏开发
Posted lovoo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 模仿flabby bird游戏开发相关的知识,希望对你有一定的参考价值。
一、示意图:
1)开始画面:
2)游戏中画面:
3)结束画面:
二、分析:
1、游戏中的每个元素都可封装成对象,
1)开始按钮与结束按钮可封装成GameButton对象:
属性有:有坐标x,y;有原图与按下后的图片;另外还有判断是否点击了的属性
方法有:draw方法,用来绘制自己; isClick判断是否被点击了
另外提供点击的监听事件OnButtonClickListener
2)Bird对象:
属性有图片,坐标,位置,大小等
方法有draw方法,resetHeigt方法(用于在游戏结束后恢复其高度)
3)Floor地板对象:
属性有:坐标,BitmapShader填充物
方法有:draw方法,游戏运行时不断绘制,看起来想不断的移动
4)Grade分数对象
属性有:分数图片,宽高,单个分数的矩阵
方法有:draw方法,绘制分数从左到右绘制,每绘制一个分数,移动到下个分数,宽度是单个分数的宽度
5)管道对象
属性有:上管道高度,上管道与下管道之间的距离,图片
方法有:draw方法,根据随机数绘制管道;touchBird方法,判断小鸟是否触碰到了管道
2、游戏绘制在SurfaceView界面上
1)创建类FlyBirdView并继承SurfaceView 实现接口Callback, Runnable
2)在子线程里绘制绘制上面的对象
3)在onSizeChanged方法里初始化所有的对象,因为在这个方法里控件的宽高固定了下来
4)在构造函数里初始化图片等基本属性
3、除了绘制之外,游戏是有状态的,一般来说,游戏有三种状态:等待状态、运行状态和结束状态
在这里我们使用emum来设值,并且进入游戏时默认是等待状态
1)在等待状态里最主要绘制开始按钮
3)运行状态主要是对管道、地板等对象的不断绘制
3)结束状态绘制gameovew和重新开始的按钮
三、实体类代码:
1)Bird类:
/**
* 鸟的实体类
*
* @Project App_View
* @Package com.android.view.flybird
* @author chenlin
* @version 1.0
* @Date 2014年5月6日
*/
public class Bird {
public static final float RADIO_POS_HEIGHT = 1 / 3f;// 鸟所在的默认屏幕高度
private static final int BIRD_SIZE = 30; // 鸟的宽度 30dp
private Bitmap mBirdBitmap;// 鸟图片
private int mHeight;// 鸟高度
private int mWidth;// 鸟宽度
private RectF mBirdRectF; // 鸟所在的范围
private int x, y;// 所在坐标
private int mGameHeight;
public Bird(Context context, Bitmap bitmap, int gameWidth, int gameHeight) {
this.mBirdBitmap = bitmap;
this.mWidth = UITools.dip2px(context, BIRD_SIZE);
this.mHeight = (int) (mWidth * 1.0f / bitmap.getWidth() * bitmap.getHeight());
// 给坐标赋值
this.x = gameWidth / 2 - bitmap.getWidth() / 2;
this.y = (int) (gameHeight * RADIO_POS_HEIGHT);
this.mBirdRectF = new RectF();
this.mGameHeight = gameHeight;
}
/**
* 绘制鸟
*
* @param canvas
*/
public void draw(Canvas canvas) {
mBirdRectF.set(x, y, x + mWidth, y + mHeight);
canvas.drawBitmap(mBirdBitmap, null, mBirdRectF, null);
}
public void resetHeigt() {
y = (int) (mGameHeight * RADIO_POS_HEIGHT);
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getWidth() {
return mWidth;
}
public int getHeight() {
return mHeight;
}
}
2)Floor类
/**
* 地板
*
* @Project App_View
* @Package com.android.view.flybird
* @author chenlin
* @version 1.0
* @Date 2014年5月6日
*/
public class Floor {
// 地板位置游戏面板高度的4/5到底部
private static final float FLOOR_Y_POS_RADIO = 4 / 5F; // height of 4/5
private int x, y;// 坐标
private BitmapShader mBitmapShader;// 填充物
private int mGameWidth;// 地板宽高
private int mGameHeight;
public Floor(int gameWidth, int gameHeight, Bitmap bgBitmap) {
this.mGameHeight = gameHeight;
this.mGameWidth = gameWidth;
this.y = (int) (mGameHeight * FLOOR_Y_POS_RADIO);
mBitmapShader = new BitmapShader(bgBitmap, TileMode.CLAMP, TileMode.CLAMP);
}
/**
* 绘制自己
*
* @param canvas
*/
public void draw(Canvas canvas, Paint paint) {
// 进行平移,如果移出的部分超过屏幕的宽度,就重新让坐标移动到源位置
if (-x > mGameWidth) {
x = x % mGameWidth;
}
/**
* save() : 用来保存Canvas的状态,save()方法之后的代码,可以调用Canvas的平移、放缩、旋转、裁剪等操作!
*/
canvas.save(Canvas.MATRIX_SAVE_FLAG);
//平移到指定位置
canvas.translate(x, y);
paint.setShader(mBitmapShader);
canvas.drawRect(x, 0, -x + mGameWidth, mGameHeight - y, paint);
/**
* restore():用来恢复Canvas之前保存的状态(可以想成是保存坐标轴的状态),防止save()方法代码之后对Canvas执行的操作,继续对后续的绘制会产生影响,通过该方法可以避免连带的影响
*/
canvas.restore();
paint.setShader(null);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
}
3)GameButton类
/**
* 开始按钮
* @Project App_View
* @Package com.android.view.flybird
* @author chenlin
* @version 1.0
* @Date 2014年5月19日
*/
public class GameButton {
private int x;//所在坐标
private int y;
private Bitmap mBitmap;//原来按钮图片
private Bitmap mPressBitmap;//按下的按钮图片
private RectF mRectF; // 按钮所在的范围
private boolean isClick = false;//判断是否被点击了
public GameButton(Bitmap bitmap, Bitmap pressBitmap, int gameWidth, int gameHeight){
this.mBitmap = bitmap;
this.mPressBitmap = pressBitmap;
this.x = gameWidth/2-mBitmap.getWidth()/2;//左边距
this.y = gameHeight;//初始的位置在屏幕最下端
this.mRectF = new RectF();
}
/**
* 绘制自己
* @param canvas
*/
public void draw(Canvas canvas){
canvas.save(Canvas.MATRIX_SAVE_FLAG);
mRectF.set(x, y, x + mBitmap.getWidth(), y + mBitmap.getHeight());
if (isClick) {
canvas.drawBitmap(mBitmap, null , mRectF, null);
}else {
canvas.drawBitmap(mPressBitmap, null , mRectF, null);
}
canvas.restore();
}
/**
* 判断按钮是否可点击
* @return
*/
public boolean isClick(int newX, int newY) {
Rect rect = new Rect(x, y, x + mPressBitmap.getWidth(), y + mPressBitmap.getHeight());
isClick = rect.contains(newX, newY);
return isClick;
}
public void setClick(boolean isClick) {
this.isClick = isClick;
}
/**
* 提供向外的点击事件
*/
public void click(){
if (mListener != null) {
mListener.click();
}
}
private OnButtonClickListener mListener;
public interface OnButtonClickListener{
void click();
}
public void setOnButtonClickListener(OnButtonClickListener listener){
this.mListener = listener;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
4)分数Grade类:
/**
* 分数
*
* @Project App_View
* @Package com.android.view.flybird
* @author chenlin
* @version 1.0
* @Date 2016年5月16日
*/
public class Grade {
private Bitmap[] mNumBitmap;//所有分数的图片集合
private RectF mSingleNumRectF;//单个分数的矩阵
private int mSingleGradeWidth;//单个分数的宽度
private int mGameWidth;
private int mGameHeight;
public Grade(Bitmap[] numBitmap, RectF rectF, int singleGradeWidth, int gameWidth, int gameHeight) {
this.mNumBitmap = numBitmap;
this.mSingleNumRectF = rectF;
this.mSingleGradeWidth = singleGradeWidth;
this.mGameWidth = gameWidth;
this.mGameHeight = gameHeight;
}
/**
* 绘制
*
* @param mCanvas, int gameWidth
*/
public void draw(Canvas canvas, int score) {
String grade = score + "";
canvas.save(Canvas.MATRIX_SAVE_FLAG);
//移动屏幕的中间,1/8的高度
canvas.translate(mGameWidth / 2 - grade.length() * mSingleGradeWidth / 2, 1f / 8 * mGameHeight);
// 依次绘制分数
for (int i = 0; i < grade.length(); i++) {
//100,先绘制1,
String numStr = grade.substring(i, i + 1);
int num = Integer.valueOf(numStr);
canvas.drawBitmap(mNumBitmap[num], null, mSingleNumRectF, null);
//移动到下一个分数0
canvas.translate(mSingleGradeWidth, 0);
}
canvas.restore();
}
}
5)管道类Pipe:
/**
* 管道实体
*
* @Project App_View
* @Package com.android.view.flybird
* @author chenlin
* @version 1.0
* @Date 2014年5月7日
*/
public class Pipe {
private static final float RADIO_BETWEEN_UP_DOWN = 1 / 5F;// 上下管道间的距离
private static final float RADIO_MAX_HEIGHT = 2 / 5F;// 上管道的最大高度
private static final float RADIO_MIN_HEIGHT = 1 / 5F;// 上管道的最小高度
private int x;// 管道x坐标
private int mTopHeight;// 上管道高度
private int mMargin;// 上下管道的距离
private Bitmap mTopBitmap;// 上管道图片
private Bitmap mBottomBitmap;// 下管道图片
private static Random random = new Random();
public Pipe(Context context, int gameWidth, int gameHeight, Bitmap topBitmap, Bitmap bottomBitmap) {
mMargin = (int) (gameHeight * RADIO_BETWEEN_UP_DOWN);
// 默认从最左边出现 ,小鸟往前飞时,管道往左移动
x = gameWidth;
mTopBitmap = topBitmap;
mBottomBitmap = bottomBitmap;
// 高度随机
randomHeight(gameHeight);
}
/**
* 随机生成一个高度
*/
private void randomHeight(int gameHeight) {
mTopHeight = random.nextInt((int) (gameHeight * (RADIO_MAX_HEIGHT - RADIO_MIN_HEIGHT)));
mTopHeight = (int) (mTopHeight + gameHeight * RADIO_MIN_HEIGHT);
}
public void draw(Canvas canvas, RectF rect) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
// rect为整个管道,假设完整管道为100,需要绘制20,则向上偏移80 rect.bottom管的实际高度
canvas.translate(x, -(rect.bottom - mTopHeight));
// 绘制上管道
canvas.drawBitmap(mTopBitmap, null, rect, null);
// 下管道,偏移量为,上管道高度+margin
canvas.translate(0, rect.bottom + mMargin);
//canvas.translate(0, mTopHeight + mMargin);
//绘制下管道
canvas.drawBitmap(mBottomBitmap, null, rect, null);
canvas.restore();
}
/**
* 判断和鸟是否触碰
* @param bird
* @return
*/
public boolean touchBird(Bird bird){
/**
* 如果bird已经触碰到管道
*/
if (bird.getX() + bird.getWidth() > x && (bird.getY() < mTopHeight || bird.getY() + bird.getHeight() > mTopHeight + mMargin)) {
return true;
}
return false;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
}
四、具体实现:
1)我们先从简单的开始,实现游戏最基本的配置
public class FlyBirdView extends SurfaceView implements Callback, Runnable {
private SurfaceHolder mHolder;
// private Thread mThread;
private ExecutorService mPool;
private Canvas mCanvas;
private boolean isRunnging;// 是否运行
// 二.设置背景
private Bitmap mBgBitmap;
//当前View的尺寸
private int mWidth;
private int mHeight;
private RectF mGamePanelRect = new RectF();
// ----构造函数处理---------------------------------------------
public FlyBirdView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlyBirdView(Context context) {
this(context, null);
}
public FlyBirdView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
// -初始化holer-----------------------
mHolder = getHolder();
mHolder.addCallback(this);
setZOrderOnTop(true);
// 设置画布 背景透明
mHolder.setFormat(PixelFormat.TRANSLUCENT);
// --焦点设置----------------------------
setFocusable(true);
// 设置触屏
setFocusableInTouchMode(true);
// 设置常亮
setKeepScreenOn(true);
// --背景设置--------------------------------
mGamePanelRect = new RectF();
mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bgbird);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mWidth = w;
mHeight = h;
mGamePanelRect.set(0, 0, w, h);
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
public void run() {
while (isRunnging) {
long start = System.currentTimeMillis();
draw();
long end = System.currentTimeMillis();
if (start - end < 50) {
SystemClock.sleep(50 - (start - end));
}
}
}
private void draw() {
try {
if (mHolder != null) {
mCanvas = mHolder.lockCanvas();
if (mCanvas != null) {
//绘制背景
drawBg();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mHolder != null && mCanvas != null) {
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
private void drawBg() {
mCanvas.drawBitmap(mBgBitmap,null, mGamePanelRect, null);
}
// ---callback监听------------------------------------------------------
@Override
public void surfaceCreated(SurfaceHolder holder) {
// -线程处理--------------------------
isRunnging = true;
mPool = Executors.newFixedThreadPool(5);
// mThread = new Thread(this);
// mThread.start();
mPool.execute(this);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// 通知关闭线程
isRunnging = false;
}
}
2)在画布上添加对象
/**
* 游戏主界面的绘制
*
* @Project App_View
* @Package com.android.view.flybird
* @author chenlin
* @version 1.0
* @Date 2014年5月7日
*/
public class FlyBirdView1 extends SurfaceView implements Callback, Runnable {
private SurfaceHolder mHolder;
// private Thread mThread;
private ExecutorService mPool;
private Canvas mCanvas;
private boolean isRunnging;// 是否运行
// 二.设置背景
private Bitmap mBgBitmap;
// 当前View的尺寸
private int mWidth;
private int mHeight;
private RectF mGamePanelRect = new RectF();
// 三、设置鸟
private Bird mBird;
private Bitmap mBirdBitmap;
// 四、添加地板
private Floor mFloor;
private Bitmap mFloorBitmap;
// 五、添加管道
/** 管道的宽度 60dp */
private static final int PIPE_WIDTH = 60;
private Pipe mPipe;
/** 上管道的图片 */
private Bitmap mPipeTopBitmap;
/** 下管道的图片 */
private Bitmap mPipeBotBitmap;
/** 管道的宽度 */
private int mPipeWidth;
/** 管道矩阵 */
private RectF mPipeRectF;
/** 管道集合 */
private List<Pipe> mPipeList;
// 六、添加分数
/** 分数 */
private final int[] mNums = new int[] { R.drawable.n0, R.drawable.n1, R.drawable.n2, R.drawable.n3, R.drawable.n4, R.drawable.n5,
R.drawable.n6, R.drawable.n7, R.drawable.n8, R.drawable.n9 };
private Grade mGrade;
/** 分数图片组 */
private Bitmap[] mNumBitmap;
/** 分值 */
private int mScore = 100;
/** 单个数字的高度的1/15 */
private static final float RADIO_SINGLE_NUM_HEIGHT = 1 / 15f;
/** 单个数字的宽度 */
private int mSingleGradeWidth;
/** 单个数字的高度 */
private int mSingleGradeHeight;
/** 单个数字的范围 */
private RectF mSingleNumRectF;
// ----构造函数处理---------------------------------------------
public FlyBirdView1(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FlyBirdView1(Context context) {
super(context);
init();
}
public FlyBirdView1(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
// -初始化holer-----------------------
mHolder = getHolder();
mHolder.addCallback(this);
setZOrderOnTop(true);
// 设置画布 背景透明
mHolder.setFormat(PixelFormat.TRANSLUCENT);
// --焦点设置----------------------------
setFocusable(true);
// 设置触屏
setFocusableInTouchMode(true);
// 设置常亮
setKeepScreenOn(true);
// --背景设置--------------------------------
mGamePanelRect = new RectF();
mBgBitmap = loadImageByResId(R.drawable.bg1);
// --添加鸟的图片---
mBirdBitmap = loadImageByResId(R.drawable.b1);
// --添加地板---
mFloorBitmap = loadImageByResId(R.drawable.floor_bg2);
// --管道的宽度初始化--
mPipeWidth = UITools.dip2px(getContext(), PIPE_WIDTH);
// --添加管道图片--
mPipeTopBitmap = loadImageByResId(R.drawable.g2);
mPipeBotBitmap = loadImageByResId(R.drawable.g1);
mPipeList = new ArrayList<Pipe>();
// -------------------------------------------------------
// 初始化分数图片
mNumBitmap = new Bitmap[mNums.length];
for (int i = 0; i < mNums.length; i++) {
mNumBitmap[i] = loadImageByResId(mNums[i]);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
mGamePanelRect.set(0, 0, w, h);
// 初始化鸟
mBird = new Bird(getContext(), mBirdBitmap, mWidth, mHeight);
// 初始化地板
mFloor = new Floor(mWidth, mHeight, mFloorBitmap);
// 初始化管道范围
mPipeRectF = new RectF(0, 0, mPipeWidth, mHeight);
// 初始化 管道
mPipe = new Pipe(getContext(), mWidth, mHeight, mPipeTopBitmap, mPipeBotBitmap);
mPipeList.add(mPipe);
// 初始化分数
mSingleGradeHeight = (int) (h * RADIO_SINGLE_NUM_HEIGHT);// 屏幕的1/15
mSingleGradeWidth = (int) (mNumBitmap[0].getWidth() * (1.0f * mSingleGradeHeight / mNumBitmap[0].getHeight()));
mSingleNumRectF = new RectF(0, 0, mSingleGradeWidth, mSingleGradeHeight);
mGrade = new Grade(mNumBitmap, mSingleNumRectF, mSingleGradeWidth, mWidth, mHeight);
}
@Override
public void run() {
while (isRunnging) {
long start = System.currentTimeMillis();
draw();
long end = System.currentTimeMillis();
if (end - start < 50) {
SystemClock.sleep(50 - (end - start));
}
}
}
private void draw() {
try {
Logger.i("bird", "mHolder==" + mHolder);
if (mHolder != null) {
mCanvas = mHolder.lockCanvas();
Logger.i("bird", "mCanvas==" + mCanvas);
if (mCanvas != null) {
drawBg(); // 绘制背景
drawBird();// 绘制鸟
drawFloor();// 绘制地板
drawPipes();// 绘制管道
drawGrades();// 绘制分数
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mHolder != null && mCanvas != null) {
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
/**
* 绘制分数
*/
private void drawGrades() {
mGrade.draw(mCanvas, mScore);
}
private int mSpeed = UITools.dip2px(getContext(), 2);
private void drawFloor() {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
mFloor.draw(mCanvas, paint);
// 更新我们地板绘制的x坐标
mFloor.setX(mFloor.getX() - mSpeed);
}
private void drawBird() {
mBird.draw(mCanvas);
}
private void drawBg() {
mCanvas.drawBitmap(mBgBitmap, null, mGamePanelRect, null);
}
private void drawPipes() {
for (Pipe pipe : mPipeList) {
// 先设定x坐标
pipe.setX(pipe.getX() - mSpeed);
pipe.draw(mCanvas, mPipeRectF);
}
}
// ---callback监听------------------------------------------------------
@Override
public void surfaceCreated(SurfaceHolder holder) {
// -线程处理--------------------------
isRunnging = true;
mPool = Executors.newFixedThreadPool(5);
mPool.execute(this);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// 通知关闭线程
isRunnging = false;
}
/**
* 根据resId加载图片
*
* @param resId
* @return
*/
private Bitmap loadImageByResId(int resId) {
return BitmapFactory.decodeResource(getResources(), resId);
}
}
3)在画布上增加状态信息和开始与结束界面,游戏主界面就完成了
/**
* 游戏主界面
*
* @Project App_View
* @Package com.android.view.flybird
* @author chenlin
* @version 1.0
* @Date 2014年5月7日
*/
public class FlyBirdView extends SurfaceView implements Callback, Runnable {
//private static final String TAG = "bird";
private SurfaceHolder mHolder;
private ExecutorService mPool;
private Canvas mCanvas;
private boolean isRunnging;// 是否运行
// 二.设置背景
private Bitmap mBgBitmap;
// 当前View的尺寸
private int mWidth;
private int mHeight;
private RectF mGamePanelRect = new RectF();
// 三、设置鸟
private Bird mBird;
private Bitmap mBirdBitmap;
// 四、添加地板
private Floor mFloor;
private Bitmap mFloorBitmap;
// 五、添加管道
/** 管道的宽度 60dp */
private static final int PIPE_WIDTH = 60;
private Pipe mPipe;
/** 上管道的图片 */
private Bitmap mPipeTopBitmap;
/** 下管道的图片 */
private Bitmap mPipeBotBitmap;
/** 管道的宽度 */
private int mPipeWidth;
/** 管道矩阵 */
private RectF mPipeRectF;
/** 管道集合 */
private List<Pipe> mPipeList;
/** 管道移动的速度 */
private int mSpeed = UITools.dip2px(getContext(), 5);
// 六、添加分数
/** 分数 */
private final int[] mNums = new int[] { R.drawable.n0, R.drawable.n1, R.drawable.n2, R.drawable.n3, R.drawable.n4, R.drawable.n5,
R.drawable.n6, R.drawable.n7, R.drawable.n8, R.drawable.n9 };
private Grade mGrade;
/** 分数图片组 */
private Bitmap[] mNumBitmap;
/** 分值 */
private int mScore = 0;
/** 单个数字的高度的1/15 */
private static final float RADIO_SINGLE_NUM_HEIGHT = 1 / 15f;
/** 单个数字的宽度 */
private int mSingleGradeWidth;
/** 单个数字的高度 */
private int mSingleGradeHeight;
/** 单个数字的范围 */
private RectF mSingleNumRectF;
// --七、添加游戏的状态-------------------------------------------------------------------------
/** 刚进入游戏时是等待静止的状态 */
private GameStatus mStatus = GameStatus.WAITING;
private enum GameStatus {
WAITING, RUNNING, OVER
}
/** 触摸上升的距离,因为是上升,所以为负值 */
private static final int TOUCH_UP_SIZE = -16;
/** 将上升的距离转化为px;这里多存储一个变量,变量在run中计算 */
private final int mBirdUpDis = UITools.dip2px(getContext(), TOUCH_UP_SIZE);
/** 跳跃的时候的临时距离 */
private int mTmpBirdDis;
// --八、按钮----------------------------------------
private GameButton mStart;
private Bitmap mStartBitmap;
private Bitmap mStartPressBitmap;// 开始按下图片
private GameButton mRestart;
private Bitmap mRestartBitmap;
private Bitmap mRestartPressBitmap;// 从新开始按下图片
// --九、游戏中的变量---------------------------
/** 两个管道间距离 **/
private final int PIPE_DIS_BETWEEN_TWO = UITools.dip2px(getContext(), 300);
/** 鸟自动下落的距离 */
private final int mAutoDownSpeed = UITools.dip2px(getContext(), 2);
//private Handler mHandler = new Handler();
// ----构造函数处理---------------------------------------------
public FlyBirdView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FlyBirdView(Context context) {
super(context);
init();
}
public FlyBirdView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
// ---初始化开始 ----------------------------------------------------------
private void init() {
// -初始化holer-----------------------
mHolder = getHolder();
mHolder.addCallback(this);
setZOrderOnTop(true);
// 设置画布 背景透明
mHolder.setFormat(PixelFormat.TRANSLUCENT);
// --焦点设置----------------------------
setFocusable(true);
// 设置触屏
setFocusableInTouchMode(true);
// 设置常亮
setKeepScreenOn(true);
// --背景设置--------------------------------
mGamePanelRect = new RectF();
mBgBitmap = loadImageByResId(R.drawable.bg1);
// --添加鸟的图片---
mBirdBitmap = loadImageByResId(R.drawable.b1);
// --添加地板---
mFloorBitmap = loadImageByResId(R.drawable.floor_bg2);
// --管道的宽度初始化--
mPipeWidth = UITools.dip2px(getContext(), PIPE_WIDTH);
// --添加管道图片--
mPipeTopBitmap = loadImageByResId(R.drawable.g2);
mPipeBotBitmap = loadImageByResId(R.drawable.g1);
mPipeList = new ArrayList<Pipe>();
// -------------------------------------------------------
// 初始化分数图片
mNumBitmap = new Bitmap[mNums.length];
for (int i = 0; i < mNums.length; i++) {
mNumBitmap[i] = loadImageByResId(mNums[i]);
}
// ---初始化按钮图片-------------------------------------
mStartBitmap = BitmapUtil.getImageFromAssetsFile(getContext(), "start.png");
mStartPressBitmap = BitmapUtil.getImageFromAssetsFile(getContext(), "start2.png");
mRestartBitmap = BitmapUtil.getImageFromAssetsFile(getContext(), "restart1.png");
mRestartPressBitmap = BitmapUtil.getImageFromAssetsFile(getContext(), "restart2.png");
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
mGamePanelRect.set(0, 0, w, h);
// 初始化鸟
mBird = new Bird(getContext(), mBirdBitmap, mWidth, mHeight);
// 初始化地板
mFloor = new Floor(mWidth, mHeight, mFloorBitmap);
// 初始化管道范围
mPipeRectF = new RectF(0, 0, mPipeWidth, mHeight);
// 初始化 管道
mPipe = new Pipe(getContext(), mWidth, mHeight, mPipeTopBitmap, mPipeBotBitmap);
mPipeList.add(mPipe);
// 初始化分数
mSingleGradeHeight = (int) (h * RADIO_SINGLE_NUM_HEIGHT);// 屏幕的1/15
mSingleGradeWidth = (int) (mNumBitmap[0].getWidth() * (1.0f * mSingleGradeHeight / mNumBitmap[0].getHeight()));
mSingleNumRectF = new RectF(0, 0, mSingleGradeWidth, mSingleGradeHeight);
mGrade = new Grade(mNumBitmap, mSingleNumRectF, mSingleGradeWidth, mWidth, mHeight);
// 初始化按钮
mStart = new GameButton(mStartBitmap, mStartPressBitmap, mWidth, mHeight);
// 从新开始按钮
mRestart = new GameButton(mRestartBitmap, mRestartPressBitmap, mWidth, mHeight);
if (mStatus == GameStatus.WAITING && mStart != null) {
以上是关于Android 模仿flabby bird游戏开发的主要内容,如果未能解决你的问题,请参考以下文章