2021SC@SDUSC
目录
案例——Flappybird
绘制结果展示:
1.SurfaceView的使用方法
使用方法:
1、继承SurfaceView,实现SurfaceHolder.Callback接口
2、重写以下方法:
surfaceChanged:在surface大小或者格式发生变化时触发,在surfaceCreated调用后至少会被调用一次。
surfaceCreated:surface创建时触发,一般在此函数中开启绘图线程(新的线程,不要再这个线程中绘制surface)
surfaceDestoryed:销毁时触发,一般不可见时就会销毁。
3、利用getHolder()获取SurfaceHolder对象,调用SurfaceHolder.addCallback添加回调。
4、SurfaceHolder.lockCanvas获取Canvas对象并锁定画布,调用Canvas绘图,SurfaceHolder.unlockCanvasAndPost结束锁定画布,提交改变。
SurfaceView vs View
它和View有一个很大的区别,View在UI线程去更新自己;而SurfaceView则在一个子线程中去更新自己;这也显示出了它的优势,当制作游戏等需要不断刷新View时,因为是在子线程,避免了对UI线程的阻塞。
2.在MainActivity中显示SurfaceView
public class B_MainActivity extends AppCompatActivity {
GameFlappyBird mGame;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
checkPermission();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
mGame=new GameFlappyBird(this);
setContentView(mGame);
}
}
MainActivity 作为主界面,通过setContentView(mGame);来设置SurfaceView为主页面展示。
3.绘制背景
(1)成员变量
//背景相关
private Bitmap mBackgroud_bitmap;
private int mWidth,mHeight;
private RectF mGamePanelRect=new RectF();
Bitmap背景图成员;
需要获取当前View的尺寸 width,height;
设置绘画区域的RecF类成员。
(2)加载图片、初始化图片的方法
//加载图片
private Bitmap loadBitmapByResId(int resId){
return BitmapFactory.decodeResource(getResources(), resId);
}
//初始化图片
private void initBitmap(){
mBackgroud_bitmap=loadBitmapByResId(R.drawable.bg1);
mBird_bitmap=loadBitmapByResId(R.drawable.b1);
mPipeTop=loadBitmapByResId(R.drawable.g2);
mPipeBottom=loadBitmapByResId(R.drawable.g1);
}
(3)在Surface创建时初始化Bitmap
initBitmap();
(4)设置背景长宽,初始化尺寸
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);
}
(5)画背景
//画背景
private void drawBg(){
mCanvas.drawBitmap(mBackgroud_bitmap,null,mGamePanelRect,null);
}
private void draw()
{
try
{
// 获得canvas
mCanvas = mHolder.lockCanvas();
if (mCanvas != null)
{
// drawSomething..
drawBg();
}
} catch (Exception e)
{
} finally
{
if (mCanvas != null)
mHolder.unlockCanvasAndPost(mCanvas);
}
}
4.绘制鸟
(1)鸟的变量
//鸟相关
private Bird bird;
private Bitmap mBird_bitmap;
(2)初始化鸟的对象
public Bird(Context context,int gameWidth,int gameHeight,Bitmap bitmap){
this.bitmap=bitmap;
//鸟的位置
x=(gameWidth/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());
}
鸟在屏幕高度2/3的位置。
(3)画鸟
//画鸟
private void drawBird(){
bird.draw(mCanvas);
}
5.绘制管道
(1)变量
上管道的高度(管道长度时随机生成的,设置一个最大值、最小值);
上管道最大高度4/5F,上管道最小高度1/5F;
管道间隙长度;
下管道长度:用背景长度-(上管道长度+管道间隙长度)计算;
上下管道的图片;
管道横坐标
(2)为管道随机生成一个高度
private void randomHeight(int gameHeight){
height=random.nextInt((int)(gameHeight*(RADIO_MAX_HEIGHT-RASIO_MIN_HEIGHT)));
height=(int)(height+gameHeight*RASIO_MIN_HEIGHT);
}
(3)构造函数
public Pipe(Context context,int gameWidth,int gameHeight,Bitmap top,Bitmap bottom){
//间隙是默认值
margin=(int)(gameHeight*RADIO_BETWEEN_UP_DOWN);
//默认从最右边出现
x=gameWidth;
//图片参数
mTop=top;
mBottom=bottom;
//随机设置上管道高度
randomHeight(gameHeight);
}
(4)画自己
public void draw(Canvas mCanvas, RectF rectF){
mCanvas.save();
//rect为整个管道
mCanvas.translate(x,-(rectF.bottom-height));
mCanvas.drawBitmap(mTop,null,rectF,null);
//下管道
mCanvas.translate(0,(rectF.bottom-height)+height+margin);
mCanvas.drawBitmap(mBottom,null,rectF,null);
mCanvas.restore();
}
(5)在主类中初始化自己
private void drawPipes(){
//画出管道List中的每一个
for(Pipe pipe:mPipes){
pipe.setX(pipe.getX()-mSpeed);
pipe.draw(mCanvas,mPipeRect);
}
}