您的位置:首页 > 其它

SurfaceView 游戏开发的一些基础知识和注意事项

2017-04-12 15:04 676 查看
  surfaceview 是游戏开发和视频播放常用的控件,因此我们要自己开发一些小游戏或者视频播放器多用来继承该view,并添加自己的独特功能。下面就以做游戏的框架来介绍:

先介绍一些基础知识:

1、继承surfaceview的view(就简称MyView),要想在布局文件中能使用,我们要覆写surfacview的构造方法:

public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}


2、当系统在加载游戏时候,比如初始化MyView的时候需要时间,为了去掉游戏开始前短暂的黑屏情况,我们通常写一个欢迎界面,或者写一个关级等,方法有很多,我们可以用一个比较简单的方法:
 在布局文件里加上我们的surfacview和关级或者图片的控件。初始的时候将Myview设置为Gone , 其他的设置为Visibale。在resume里面开始准备我们的MyView游戏里面图片、声音等素材的加载(注意设置标志位,否则home再次进入的时候会又初始化导致游戏数据混乱)。然后在利用handler异步发送消息,当我们的MyView的游戏素材加载完了,就发送消息,将Myview设置为Visiable,将其他的设置为Gone。(在刚开始没有想到思路的时候利用setContentView()2次,发现就是resume()设置的一次生效,主要是我们的界面显示是在Onresume()方法执行完后,因此前面我们设置布局文件只是加载进资源初始化一些数据)。

3、surfacview占用系统资源比较大,当应用失去屏幕焦点的时候,如:按下home键,电源键、back键时候就会回收,且surfaceView的显示主要是通过surfacHolder来锁定和绘画画布来控制的,而为了更好的控制surfacview的画面通常添加一个回调方法来处理事情:addCallback(new CallBack()),而实现callBack得实现它的三个方法:

class MyCallBack implements SurfaceHolder.Callback
{
@Override
public void surfaceCreated(SurfaceHolder holder) {
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}


  为了让我们的游戏在后台运行后重新进入时能够继续,就得了解我们按下home、电源键后的生命周期:(只要不重新执行view的构造函数我们的游戏就可以继续玩,前提是我们的绘画线程中的数据不能乱

程序第一次启动时,调用view的构造函数->surfaceCreated->surfaceChanged

按下home键时:执行surfaceDestroyed;点击图标返回程序时,调用surfaceCreated->surfaceChanged

  解决办法:发现surfacview并不会重新执行构造函数,因此只要我们的绘图线程重新启动,且之前的游戏数据不乱就可以继续玩了: (后面的解决办法都是基于满足home键解决方案上)  

    (1)将线程设为view的成员

    (2)在surfaceCreated中把线程new出来,并设置运行标志true、调用线程的start(不要在构造函数中new)

    (3)在surfaceDestroyed中将运行标志设为false

按返回键时,调用surfaceDestroyed;点击图标返回程序时,调用view的构造函数->调用surfaceCreated->surfaceChanged

  解决办法:back键默认是退出游戏,若想按下back键后台运行就得覆写OnBackPressed() 方法里写moveTaskToBack()。

  效果:surfaceDestroyed ;点击图标进入时候:surfaceCreated->surfaceChanged

按下电源键锁频时:surfaceDestroyed,解锁进入游戏时:surfaceCreated->surfaceChanged

  解决办法:1、为了锁屏时,不重新初始化surfacview,我们可以在清单文件activity里添加:android:configChanges="orientation|keyboardHidden|screenSize" ,因为锁屏引起的也是screenSize的变化导致,添加后就是屏幕的变化不影响游戏。

  效果:按电源键时 surfaceChanged,点击进入时:surfaceChanged

Node: 1、有时候我们玩游戏的时候,想要休息一会就暂停了,等几分钟玩的时候会发现屏幕黑了,因此我们可以在activity里用 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 让屏幕长亮)

    2、 为了在绘图的时候后台运行等不相互影响,在构造函数的时候需要init()游戏里的所有素材。

class MyCallBack implements SurfaceHolder.Callback
{
@Override
public void surfaceCreated(SurfaceHolder holder) {
isRunning = true;
drawThread = new Thread(new MyRunnable());
drawThread.start();
log("surfaceCreated");
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
log("surfaceChanged");
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isRunning = false;
log("surfaceDestroyed");
}
}


4、画图

画图的时候我们先锁住画布,然后绘图,绘图完了就解除锁定并传递显示:这里是一个线程画图对一个surfacview绘图,若涉及多线程最好是在锁定屏幕到绘图完成解锁 实行同步.

class MyRunnable implements  Runnable
{
@Override
public void run() {
paint = new Paint();
paint.setColor(Color.RED);
while(isRunning)
{
canvas = surfaceHolder.lockCanvas();
if(canvas!= null)
{
canvas.drawColor(Color.WHITE);//设置背景
drawTanks(canvas, tanks, paint);
checkState(myTank , tanks);
canvas.drawBitmap(directionBt , 0 ,directionBtCenter.y -r ,paint);
canvas.drawBitmap(directionCenterBt , directionCenterBtCenter.x - r3 ,directionCenterBtCenter.y -r3 ,paint);
canvas.drawBitmap(boomBt , boomCenter.x -r2,boomCenter.y - r2,paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}

}
Log.d( Logcat , "线程运行结束");
}
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐