Android SurfaceView实战 带你玩转flabby bird
2015-01-22 21:15
495 查看
分析
仔细观察游戏,需要绘制的有:背景、地板、鸟、管道、分数;
游戏开始时:
地板给人一种想左移动的感觉;
管道与地板同样的速度向左移动;
鸟默认下落;
当用户touch屏幕时,鸟上升一段距离后,下落;
运动过程中需要判断管道和鸟之间的位置关系,是否触碰,是否穿过等,需要计算分数。
好了,大概就这么多,那我们首先开始考虑绘制~~~
3、SurfaceView的一般写法
接下来,我们首先编写下SurfaceView的一般写法:[java]
view plaincopyprint?
package com.zhy.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
public class GameFlabbyBird extends SurfaceView implements Callback, Runnable
{
private SurfaceHolder mHolder;
/**
* 与SurfaceHolder绑定的Canvas
*/
private Canvas mCanvas;
/**
* 用于绘制的线程
*/
private Thread t;
/**
* 线程的控制开关
*/
private boolean isRunning;
public GameFlabbyBird(Context context)
{
this(context, null);
}
public GameFlabbyBird(Context context, AttributeSet attrs)
{
super(context, attrs);
mHolder = getHolder();
mHolder.addCallback(this);
setZOrderOnTop(true);// 设置画布 背景透明
mHolder.setFormat(PixelFormat.TRANSLUCENT);
// 设置可获得焦点
setFocusable(true);
setFocusableInTouchMode(true);
// 设置常亮
this.setKeepScreenOn(true);
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
// 开启线程
isRunning = true;
t = new Thread(this);
t.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height)
{
// TODO Auto-generated method stub
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
// 通知关闭线程
isRunning = false;
}
@Override
public void run()
{
while (isRunning)
{
long start = System.currentTimeMillis();
draw();
long end = System.currentTimeMillis();
try
{
if (end - start < 50)
{
Thread.sleep(50 - (end - start));
}
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
private void draw()
{
try
{
// 获得canvas
mCanvas = mHolder.lockCanvas();
if (mCanvas != null)
{
// drawSomething..
}
} catch (Exception e)
{
} finally
{
if (mCanvas != null)
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
package com.zhy.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.PixelFormat; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; public class GameFlabbyBird extends SurfaceView implements Callback, Runnable { private SurfaceHolder mHolder; /** * 与SurfaceHolder绑定的Canvas */ private Canvas mCanvas; /** * 用于绘制的线程 */ private Thread t; /** * 线程的控制开关 */ private boolean isRunning; public GameFlabbyBird(Context context) { this(context, null); } public GameFlabbyBird(Context context, AttributeSet attrs) { super(context, attrs); mHolder = getHolder(); mHolder.addCallback(this); setZOrderOnTop(true);// 设置画布 背景透明 mHolder.setFormat(PixelFormat.TRANSLUCENT); // 设置可获得焦点 setFocusable(true); setFocusableInTouchMode(true); // 设置常亮 this.setKeepScreenOn(true); } @Override public void surfaceCreated(SurfaceHolder holder) { // 开启线程 isRunning = true; t = new Thread(this); t.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 通知关闭线程 isRunning = false; } @Override public void run() { while (isRunning) { long start = System.currentTimeMillis(); draw(); long end = System.currentTimeMillis(); try { if (end - start < 50) { Thread.sleep(50 - (end - start)); } } catch (InterruptedException e) { e.printStackTrace(); } } } private void draw() { try { // 获得canvas mCanvas = mHolder.lockCanvas(); if (mCanvas != null) { // drawSomething.. } } catch (Exception e) { } finally { if (mCanvas != null) mHolder.unlockCanvasAndPost(mCanvas); } } }
这个基础的类,在Android
SurfaceView实战 打造抽奖转盘已经出现过,就不多说了,大家以后写SurfaceView的相关程序,可以直接拷贝,在此类基础上编写。
4、绘制
1、绘制背景
最简单的当然是背景了,直接drawBitmap即可。我们添加需要的成员变量,以及初始化一些参数,然后添加drawBg方法,最后在draw中调用drawBg;
[java]
view plaincopyprint?
public class CopyOfGameFlabbyBird extends SurfaceView implements Callback,
Runnable
{
/**
* 当前View的尺寸
*/
private int mWidth;
private int mHeight;
private RectF mGamePanelRect = new RectF();
/**
* 背景
*/
private Bitmap mBg;
public CopyOfGameFlabbyBird(Context context, AttributeSet attrs)
{
//省略了很多代码
initBitmaps();
}
/**
* 初始化图片
*/
private void initBitmaps()
{
mBg = loadImageByResId(R.drawable.bg1);
}
private void draw()
{
//省略了很多代码
drawBg();
//省略了很多代码
}
/**
* 绘制背景
*/
private void drawBg()
{
mCanvas.drawBitmap(mBg, null, mGamePanelRect, null);
}
/**
* 初始化尺寸相关
*/
@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);
}
/**
* 根据resId加载图片
*
* @param resId
* @return
*/
private Bitmap loadImageByResId(int resId)
{
return BitmapFactory.decodeResource(getResources(), resId);
}
}
public class CopyOfGameFlabbyBird extends SurfaceView implements Callback, Runnable { /** * 当前View的尺寸 */ private int mWidth; private int mHeight; private RectF mGamePanelRect = new RectF(); /** * 背景 */ private Bitmap mBg; public CopyOfGameFlabbyBird(Context context, AttributeSet attrs) { //省略了很多代码 initBitmaps(); } /** * 初始化图片 */ private void initBitmaps() { mBg = loadImageByResId(R.drawable.bg1); } private void draw() { //省略了很多代码 drawBg(); //省略了很多代码 } /** * 绘制背景 */ private void drawBg() { mCanvas.drawBitmap(mBg, null, mGamePanelRect, null); } /** * 初始化尺寸相关 */ @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); } /** * 根据resId加载图片 * * @param resId * @return */ private Bitmap loadImageByResId(int resId) { return BitmapFactory.decodeResource(getResources(), resId); } }
基本就是添加成员变量,然后初始化,然后绘制,上述代码经过删减,贴出的都是与前面基础代码不同的部分,大家可以将代码对号入座进行填充。
好了,现在背景图绘制好了,接下来,我们绘制小鸟~~~
2、绘制bird
鸟在我们的屏幕中,初始化时需要一个位置,x上,肯定是居中,y上我们取2/3的高度;关于bird,我们单独创建一个类:
[java]
view plaincopyprint?
package com.zhy.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.RectF;
public class Bird
{
/**
* 鸟在屏幕高度的2/3位置
*/
private static final float RADIO_POS_HEIGHT = 2 / 3F;
/**
* 鸟的宽度 30dp
*/
private static final int BIRD_SIZE = 30;
/**
* 鸟的横坐标
*/
private int x;
/**
* 鸟的纵坐标
*/
private int y;
/**
* 鸟的宽度
*/
private int mWidth;
/**
* 鸟的高度
*/
private int mHeight;
/**
* 鸟的bitmap
*/
private Bitmap bitmap;
/**
* 鸟绘制的范围
*/
private RectF rect = new RectF();
public Bird(Context context, int gameWith, int gameHeight, Bitmap bitmap)
{
this.bitmap = bitmap;
//鸟的位置
x = gameWith / 2 - bitmap.getWidth() / 2;
y = (int) (gameHeight * RADIO_POS_HEIGHT);
// 计算鸟的宽度和高度
mWidth = Util.dp2px(context, BIRD_SIZE);
mHeight = (int) (mWidth * 1.0f / bitmap.getWidth() * bitmap.getHeight());
}
/**
* 绘制自己
*
* @param canvas
*/
public void draw(Canvas canvas)
{
rect.set(x, y, x + mWidth, y + mHeight);
canvas.drawBitmap(bitmap, null, rect, null);
}
public int getY()
{
return y;
}
public void setY(int y)
{
this.y = y;
}
public int getWidth()
{
return mWidth;
}
public int getHeight()
{
return mHeight;
}
}
package com.zhy.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.RectF; public class Bird { /** * 鸟在屏幕高度的2/3位置 */ private static final float RADIO_POS_HEIGHT = 2 / 3F; /** * 鸟的宽度 30dp */ private static final int BIRD_SIZE = 30; /** * 鸟的横坐标 */ private int x; /** * 鸟的纵坐标 */ private int y; /** * 鸟的宽度 */ private int mWidth; /** * 鸟的高度 */ private int mHeight; /** * 鸟的bitmap */ private Bitmap bitmap; /** * 鸟绘制的范围 */ private RectF rect = new RectF(); public Bird(Context context, int gameWith, int gameHeight, Bitmap bitmap) { this.bitmap = bitmap; //鸟的位置 x = gameWith / 2 - bitmap.getWidth() / 2; y = (int) (gameHeight * RADIO_POS_HEIGHT); // 计算鸟的宽度和高度 mWidth = Util.dp2px(context, BIRD_SIZE); mHeight = (int) (mWidth * 1.0f / bitmap.getWidth() * bitmap.getHeight()); } /** * 绘制自己 * * @param canvas */ public void draw(Canvas canvas) { rect.set(x, y, x + mWidth, y + mHeight); canvas.drawBitmap(bitmap, null, rect, null); } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getWidth() { return mWidth; } public int getHeight() { return mHeight; } }
定义了一个类,代表我们的鸟,以及一堆成员变量,并且提供一个draw方法对外;
在GameFlabbyBird中,只需要,初始化我们的Bird,在draw里面调用bird.draw即可;
部分筛检后代码:
[java]
view plaincopyprint?
public class CopyOfGameFlabbyBird extends SurfaceView implements Callback,
Runnable
{
/**
* *********鸟相关**********************
*/
private Bird mBird;
private Bitmap mBirdBitmap;
/**
* 初始化图片
*/
private void initBitmaps()
{
mBg = loadImageByResId(R.drawable.bg1);
mBirdBitmap = loadImageByResId(R.drawable.b1);
}
private void draw()
{
// drawSomething..
drawBg();
drawBird();
}
private void drawBird()
{
mBird.draw(mCanvas);
}
/**
* 初始化尺寸相关
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
// 初始化mBird
mBird = new Bird(getContext(), mWidth, mHeight, mBirdBitmap);
}
}
public class CopyOfGameFlabbyBird extends SurfaceView implements Callback, Runnable { /** * *********鸟相关********************** */ private Bird mBird; private Bitmap mBirdBitmap; /** * 初始化图片 */ private void initBitmaps() { mBg = loadImageByResId(R.drawable.bg1); mBirdBitmap = loadImageByResId(R.drawable.b1); } private void draw() { // drawSomething.. drawBg(); drawBird(); } private void drawBird() { mBird.draw(mCanvas); } /** * 初始化尺寸相关 */ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // 初始化mBird mBird = new Bird(getContext(), mWidth, mHeight, mBirdBitmap); } }是不是很简单,下面看下此时效果图:
Activity里面这么调用即可:
[java]
view plaincopyprint?
package com.zhy.surfaceViewDemo;
import com.zhy.view.GameFlabbyBird;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity
{
GameFlabbyBird mGame;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
mGame = new GameFlabbyBird(this);
setContentView(mGame);
}
}
package com.zhy.surfaceViewDemo; import com.zhy.view.GameFlabbyBird; import android.app.Activity; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; public class MainActivity extends Activity { GameFlabbyBird mGame; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); requestWindowFeature(Window.FEATURE_NO_TITLE); mGame = new GameFlabbyBird(this); setContentView(mGame); } }
不管咋样,我们的鸟已经在指定的位置了~~~有木有一点小激动~~
下面开始添加地板;
3、绘制地板
绘制地板相比来说会难一点,因为我们需要考虑怎么让地板运动,起初我截取了两个大图,希望通过两张图不断变化,产生动画效果,but,动画的太卡,有跳跃感;于是,我忽然想到了一个东西可以做,我就把基础图变成了这样:
很小的一块图,先不考虑运动,如何填充成我们目标效果呢?
还记得有个类叫做BitmapShader么?我们可以利用它进行填充。
相关知识可以参考:Android
BitmapShader 实战 实现圆形、圆角图片
首先我们依旧是定义一个地板类:Floor
相关文章推荐
- Android SurfaceView实战 带你玩转flabby bird (上)
- Android SurfaceView实战 带你玩转flabby bird (下)
- Android SurfaceView实战 带你玩转flabby bird (上)
- Android SurfaceView实战 带你玩转flabby bird (上)
- Android SurfaceView实战 带你玩转flabby bird (下)
- Android SurfaceView实战 带你玩转flabby bird (上)
- Android SurfaceView实战 带你玩转flabby bird (下)
- Android SurfaceView实战 带你玩转flabby bird (下)
- Android SurfaceView实战 带你玩转flabby bird (上)
- Android SurfaceView实战 带你玩转flabby bird (下)
- Android SurfaceView实战 带你玩转flabby bird (下)
- Android--SurfaceView实战 打造抽奖转盘
- 玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo
- 玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo
- Android SurfaceView实战 打造抽奖转盘
- Android SurfaceView实战 打造抽奖转盘 (转)
- 玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo
- 玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo
- 【Android】SurfaceView实战 打造抽奖转盘
- Android SurfaceView实战 打造抽奖转盘