AN Game: view && SurfaceView

1、View

View 看需要重写几个函数,分别是绘图函数onDraw ,按键按下函数 onKeyDown,按键抬起函数 onKeyUp,触屏函数onTouchEvent

其中绘图函数含有画笔paint和画布canvas

@SuppressLint("DrawAllocation")
public class MyView extends View {
	 private int tX=10 , tY=10; 
     public MyView (Context context){
    	 super(context);
    	 //给当前View设置焦点,其实就是告示系统,现在这个视图需要与用户交互,让系统来监听此视图
    	 setFocusable(true);
    	 
     }
     protected void onDraw(Canvas canvas){
    	 Paint paint =new Paint();
    	 paint.setColor(Color.WHITE);
    	 canvas.drawText("HI View", tX, tY, paint);
    	 
    	 super.onDraw(canvas);
     }
     
     public boolean onKeyDown (int keyCode, KeyEvent event){
    	 //KeyEvent 指的是按键的动作事件队列,此类还定义了很多静态常量键值
    	 
    	
    	 if(keyCode == KeyEvent.KEYCODE_DPAD_UP){
    		 tY-=2;
    	 }else if(keyCode == KeyEvent.KEYCODE_DPAD_DOWN){
    		 tY+=2;
    	 }else if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
    		 tX-=2;
    	 }else if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
    		 tX+=2;
    	 }
    	 //invalidate方法不能再当前线程中 循环 调用执行,而postInvalidate()函数可以在子线程中循环调用执行
    	 //如果不在当前View创建线程循环重绘画布的话,则两种方式没有区别
    	 invalidate();
    	 //postInvalidate();
    	 return super.onKeyDown(keyCode, event);
     }
     public boolean onKeyUp(int keyCode,KeyEvent event){
    	 return super.onKeyUp(keyCode, event);
     }
     public boolean onToucnEvent(MotionEvent event){
    	 int x=(int) event.getX();
    	 int y=(int) event.getY();
    	 //玩家点击屏幕的动作
    	 if(event.getAction()==MotionEvent.ACTION_DOWN){
    		 tX=x;
    		 tY=y;
         //玩家手指抬起离开屏幕的动作		 
    	 }else if(event.getAction()==MotionEvent.ACTION_MOVE){
    		 tX=x;
     		 tY=y;
     	//玩家手指在屏幕上移动的动作
    	 }else if(event.getAction()==MotionEvent.ACTION_UP){
    		 tX=x;
     		 tY=y;
    	 }
    	 invalidate();
    	 return super.onTouchEvent(event);
     }
}

在MainActivity让屏幕显示MyView类(在这里去掉标题栏和状态栏)

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//setContentView(R.layout.activity_main);
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);
		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(new MyView(this));
		
	}
}

2、 SurfaceView

(0)SurfaceView是View的子类

(1)SurfaceHolder类提供控制SurfaceView的大小、格式等,并且主要用于监听SurfaceView的状态。

(2)SurfaceView只是保存当前视图的像素数据

(3)使用SurfaceHolder的lockCanvas()函数不仅是获取canvas,同时还对获取的 Canvas画布进行加锁,防止绘制的过程中被修改和摧毁

(4)SurfaceHolder对SurfaceView的状态进行监听需要使用android.view.SurfaceHolder.Callback接口:此接口需要重写三个函数

            当SurfaceView被创建完成后响应的函数  public void surfaceCreated(SurfaceHolder holder){}

            当SurfaceView状态发生改变时响应的函数  pubic void surfaceChanged (SurfaceHolder ,int format , int width ,int height){}

            当SurfaceView状态摧毁时响应的函数   public void surfaceDestroyed(SurfaceHolder ){}

public class MySurfaceView extends SurfaceView implements Callback{
      private SurfaceHolder sfh;
      private Paint paint;
      public MySurfaceView (Context context){
    	  super(context);
    	  sfh = this.getHolder();
    	  //为SurfaceView添加状态监听
    	  sfh.addCallback(this);
    	  paint = new Paint();
    	  paint.setColor(Color.WHITE);
      }
      public void surfaceCreated(SurfaceHolder holder){
    	  myDraw();
      }
      public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
    	  
      }
      public void surfaceDestroyed(SurfaceHolder holder){
    	  
      }
      //自定义绘图函数
      public void myDraw(){
    	  Canvas canvas = sfh.lockCanvas();
    	  canvas.drawText("HI SurfaceView", 10, 10, paint);
    	  sfh.unlockCanvasAndPost(canvas);
      }
}
刷屏的方式有几种:

(1)每次绘图之前,绘制一个等同于屏幕大小的图形或者背景图片覆盖在画布之上 

(2)每次绘图之前,在画布上填充一种颜色(肯定不是修改画笔颜色嘛),可以指定颜色也可以用RGB表示

修改后的Draw函数如下: 

public void myDrawAfterModify1(){
    	  Canvas canvas =sfh.lockCanvas();
    	  canvas.drawRect(0, 0, this.getHeight() ,this.getWidth(), paint);
    	  canvas.drawText("HI SurfaceView", tX, tY, paint);
    	  sfh.unlockCanvasAndPost(canvas);
      }
      public void myDrawAfterModify2(){
    	  Canvas canvas =sfh.lockCanvas();
    	  canvas.drawColor(Color.BLACK);
    	  canvas.drawText("HI SurfaceView", tX, tY, paint);
    	  sfh.unlockCanvasAndPost(canvas);
      }

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//setContentView(R.layout.activity_main);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(new MySurfaceView(this));
		
	}

}

3、SurfaceView视图添加线程

(1)线程的初始化和线程的启动都写在视图的SurfaceCreated创建函数当中,并且将线程标识位在视图摧毁时将其值改变为false

(2)Bcak键之后:

        surfaceDestroyed->构造函数->surfaceCreated->surfaceChanged

        Home键之后

        surfaceDestroyed->surfaceCreated->surfaceChanged

也就是说按键Back之后,surfaceView会被重新加载

(3)获取视图的宽和高

         一定要在视图创建之后才可获取到

(4)绘图函数try一下

因为当SurfaceView不可编辑或者尚未创建时,调用lockCanvas()函数会返回NULL

(5)提交画布必须放在finally下

绘图的时候可能会出现不可预知的BUG,在try下不会崩溃,但是在提交画布之前出错的话,那么解锁提交画布函数则无法被执行到,这样会导致下次通过lockCanvas来获取

Canvas时抛出异常

(6)刷帧时间尽可能保持一致


public class MySurfaceView extends SurfaceView implements Callback ,Runnable{
      private SurfaceHolder sfh;
      private Paint paint;
      private int tX=10, tY=10;
      //生命一个线程
      private Thread th;
      //线程消亡的标志位
      private boolean flag;
      private Canvas canvas;
      //声明屏幕的宽高
      private int screenW ,screenH;
      public MySurfaceView (Context context){
    	  super(context);
    	  sfh = this.getHolder();
    	  //为SurfaceView添加状态监听
    	  sfh.addCallback(this);
    	  paint = new Paint();
    	  paint.setColor(Color.WHITE);
    	  setFocusable(true);
      }
      public void surfaceCreated(SurfaceHolder holder){
    	  screenW =this.getWidth();
    	  screenH =this.getHeight();
    	  flag =true;
    	  th = new Thread(this);
    	  th.start();
    	  
      }
      public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
    	  
      }
      public void surfaceDestroyed(SurfaceHolder holder){
    	     flag=false;
      }
      //自定义绘图函数
      public void myDraw(){
    	  try{
    		  canvas = sfh.lockCanvas();
    		  if(canvas!=null){
    			  //canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), paint);
    			  canvas.drawRGB(0, 0, 0);
    			  canvas.drawText("HI GameSurfaceView", tX, tY, paint);
    		  }
    	  }catch(Exception e){
    		  
    	  }finally{
    		  if(canvas!=null)
    			  sfh.unlockCanvasAndPost(canvas);
    	  }
    	  
      }
      
      
      public boolean onTouchEvent(MotionEvent event){
    	  tX=(int) event.getX();
    	  tY=(int) event.getY();
    	  myDraw();
    	  return true;
      }
      public boolean onKeyDown(int keyCode,KeyEvent event){
    	  return super.onKeyDown(keyCode, event);
      }
      //游戏逻辑
      private void logic(){}
      
      public void run(){
    	  while(flag){
    		  long start=System.currentTimeMillis();
    		  myDraw();
    		  logic();
    		  long end= System.currentTimeMillis();
    		  try{
    			    if(end -start <50){
    			    	  Thread.sleep(50-(end-start));
    			    }
    		  }catch(InterruptedException e){
    			  e.printStackTrace();
    		  }
    	  }
      }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值