Android手机游戏开发知识点总结

Android手机游戏开发学习笔记
第一部分  其实游戏就是让状态机不断的让Canvas在View上画你想要的东西。这个状态机包括内部的执行,还包括外部的输入。
   Android开发的MVC模式
    1,通过View和SurfaceView来显示界面的视图。(处理界面与用户的交互事件,如,触笔点击,用户按键等。可通过View类的onKeyDown,onKeyUp,onTouchEvent等)。
    2,用Activity来控制游戏的整体结构。
    3,设计一个逻辑类,用来处理逻辑运算。
   Android中任何一个View类都只有重写onDraw方法来实现界面显示。
   Android中提供了onKeyUp,onKeyDown,onKeyMultiple,onKeyPreIme,onTouchEvent,onTrackballEvent等方法。可以用来处理游戏中的事件消息。所以继承View时,需要重载这些方法。
   Android中提供了invalidate来刷新界面,但invalidate不能直接在线程中调用,违背单线程模型。
    因此Android中最常用的方法是利用Handler来时更新UI界面。
    
第一部分 View 类
    每个View类都有一个绘画的画布,在游戏中可以自定义视图View,任何一个View类都只需要重写onDraw方法来实现界面显示,可以是3D,也可以是文本。
    游戏的核心就是不断的绘图和刷新,图我们可以通过onDraw方法绘制,刷新Android中可以用invalidate方法来刷新界面,注意:invalidate不能直接在线程中调用,因其违背了
    违背单线程模型。因此Android中最常用的方法是利用Handler来时更新UI界面。下面这个例子中包含了两个刷新方法。
    
   public class Game extends Activity{
    public static final int REFRESH = 1;
    public GameView gameView;
    public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     this.gameView = new GameView(this);//实例化GameView
     setContentView(gameView);
     new Thread(new GameThread()).start();
    }
   // Handler handler = new Handler(){//注释掉的为实例化Handler对象并重写handleMessage方法实现一个消息接受器,然后在线程中通过sendMessage方法发送更新界面的消息,
            当接收器收到更新界面的消息时,便执行invalidate方法更新屏幕显示。
   // public void handleMessage(Message msg){//接受消息
   //  switch (msg.what){
   //    case Game.REFRESH:
   //    gameView.invalidate();//更新界面
   //    break;
   //   }
   //   super.handleMessage(msg);
   //  }
   // };
    public boolean onTouchEvent (MotionEvent event){
     return true;  
    }
    public boolean onKeyDown(int keyCode,KeyEvent event){
     return true; 
    }
    public boolean onKeyUp(int keyCode,KeyEvent event){
     switch (keyCode){
      case KeyEvent.KEYCODE_DPAD_DOWN:
       gameView.y+=6;
       break;
      case KeyEvent.KEYCODE_DPAD_UP:
       gameView.y-=6;
       break;
     }
     return true;
    }
    public boolean onKeyMultiple(int keyCode,int repeatCount,KeyEvent event){
     return true;
    }
    
  // public class GameThread implements Runnable{//创建更新线程
  //  @Override
  //  public void run() {
  //   while(!Thread.currentThread().isInterrupted()){
  //    Message message = new Message();
  //    message.what = Game.REFRESH;
  //    Game.this.handler.sendMessage(message);//发送消息
  //    try{
  //     Thread.sleep(100);
  //    }catch(InterruptedException e){
  //     Thread.currentThread().interrupt();
  //    }
  //   }
  //  }
  // }

   public class GameThread implements Runnable{
    public void run(){
     while(!Thread.currentThread().isInterrupted()){
      try{
      Thread.sleep(100);
      }catch(InterruptedException e){
       Thread.currentThread().interrupt();
      }
      gameView.postInvalidate();//使用PostInvalidate可以直接在线程中更新界面 不需要Handler来传递消息
     } 
    }
   }
   }
   
   public class GameView extends View{
    public int count = 0;
    public int y =0;
    public GameView(Context context) {
     super(context);
    }
    public void onDraw(Canvas canvas){
     if(count<8){
      count++;
     }else{
      count=0;
     }
     Paint paint= new Paint();
     switch(count%4){
      case 0:
       paint.setColor(Color.BLACK);
       break;
      case 1:
       paint.setColor(Color.RED);
       break;
      case 2:
       paint.setColor(Color.YELLOW);
       break;
      case 3:
       paint.setColor(Color.GREEN);
       break;
     }
     canvas.drawRect(y,y,y+40,y+40, paint);//绘制矩形
    }
   }
第二部分  SurfaceView类
    1,开发复杂游戏,而且对程序的执行效率要求更高时用此类,因本身就是双缓冲机制的。
    2,SurfaceView可以直接访问一个画布。
    3,SurfaceView是提供给需要直接画像素而不是使用窗体部件的应用而使用的。
    4,View即其子类(如TextVie,Button)要画在Surface上。每个Surface创建一个Canvas对象(属性时常改变)用来管理View在Surface上绘制操作。
    5,使用SurfaceView绘图时,一般都是出现在最顶层。在使用时要对其创建,销毁,情况改变进行监视,这就需要实现SurfaceHolder.Callback接口,
     如果要对被绘制的画布进行裁剪,控制其大小时都需要使用SurfaceHolder来完成处理。
    6,在程序中,SurfaceHolder对象需要通过getHolder方法来获得,同时还需要addCallback方法来添加“回调函数”。
    7,SurfaceView与View不同之处,在于SurfaceView不需要通过线程来更新视图,在绘制前必须使用lockCanvas方法锁定画布,并得到画布,然后在画布上绘制
     绘制完成后,使用unlockCanvasAndPost方法来解锁画布。
    8,addCallback:给SurfaceView添加一个回调函数;
     removeCallback:从SurfaceView移除回调函数;

   public class GameView2 extends SurfaceView implements SurfaceHolder.Callback, Runnable{
    SurfaceHolder surfaceHolder = null;//定义对象
    public boolean loop = false;
    public int count = 1;
    public GameView2(Context context) {
     super(context);
     surfaceHolder = this.getHolder();//实例化SurfaceHolder对象
     surfaceHolder.addCallback(this);//添加回调函数
     loop = true;
     this.setFocusable(true);//不知道这句什么意思?
    }
    private void Draw() {
     Canvas canvas = surfaceHolder.lockCanvas();//锁定画布
     if(surfaceHolder ==null||canvas ==null){
      return ;
     }
     if(count<100){
      count++;
     }else{
      count= 0;
     }
     Paint paint = new Paint();//创建画笔
     paint.setAntiAlias(true);//设置抗锯齿
     paint.setColor(Color.GREEN);//设置画笔颜色 
     canvas.drawRect(0,0,320,480, paint);//绘制矩形
     switch(count%4){
      case 0:
       paint.setColor(Color.BLUE);
       break;
      case 1:
       paint.setColor(Color.YELLOW);
       break;
      case 2:
       paint.setColor(Color.RED);
       break;
      case 3:
       paint.setColor(Color.CYAN);
       break;
      default:
       paint.setColor(Color.WHITE);
       break;
     }
     canvas.drawCircle(130, 240, 500, paint);
     surfaceHolder.unlockCanvasAndPost(canvas);//绘制后解锁,绘制后必须解锁才能显示 
    }
    @Override//在Surface大小发生改变时激发
    public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
     // TODO Auto-generated method stub  
    }
    @Override//在Surface创建时激发
    public void surfaceCreated(SurfaceHolder holder) {
     // TODO Auto-generated method stub
     new Thread(this).start();
    }
    @Override//在Surface销毁时调用
    public void surfaceDestroyed(SurfaceHolder holder) {
     // TODO Auto-generated method stub
     loop=false;
    }
    public void run(){
     while(loop){
      try{
       Thread.sleep(200);
       synchronized (surfaceHolder) {
        Draw();
       }
      }catch(Exception e){
      }
     }
    }
   }
   
第三部分 Paint类和Color类
    在Android中通过graphic类来显示2D图形。graphic包括Canvas类(画布),Paint(画笔),Color(颜色),Bitmap(图像),2D几何图形等常用类。
    package graphics;
    Paint类常用的一些方法:
     setAntiAlias  设置画笔的锯齿效果
     setColor  设置画笔颜色
     setARGB 设置画笔的a,r,g,b值。
     setAlpha 设置透明度
     setTextSize 设置字体大小
     setStyle 设置画笔风格 空心或实心
     setStrokeWidth设置空心的边框宽度
     getColor 得到画笔的颜色
     getAlpha 得到画笔的透明度
    Color类中定义了一些颜色常量
     Color.rgb方法将整型的颜色转换成Color类型。如Color.red方法可提取出红色的值。
   /**
   * 注意:在绘制时按从上到下的顺序绘制的 ,后面的如果和前面的重合的话会将前面的覆盖掉
   */
   public class Graphics_Paint_Color extends View implements Runnable {
    public Paint paint;
    private String TAG="你好";
    public Graphics_Paint_Color(Context context) {
     super(context);
     paint = new Paint();//创建画笔
     new Thread(this).start();//开启线程
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     paint.setAntiAlias(true);//设置抗锯齿
     paint.setColor(Color.RED);//设置画笔颜色
     paint.setColor(Color.rgb(12, 234, 34));//设置画笔颜色 其中参数分别为red,green,blue三种颜色的值
  
     Color.red(23);//提取颜色?
     Color.blue(234);
  
     paint.setARGB(255, 23,234,49);//设置Paint的颜色和Alpha值
  
     paint.setAlpha(200);//设置透明度
  
    //paint.set(new PAINT());//设置另外一个Paint对象 
     paint.setTextSize(14);//设置字体的尺寸
   
     //得到Paint的一些属性
     Log.i(TAG, "paint的颜色"+paint.getColor());
     Log.i(TAG,"paint的Alpha"+paint.getAlpha());
  
     paint.setStyle(Paint.Style.STROKE);//设置Paint为空心
     paint.setStrokeWidth(5);//设置空心的外框宽度
     canvas.drawRect(0,0,50,60, paint);//绘制空心矩形
  
     paint.setStyle(Paint.Style.FILL);//设置Paint为实心
     canvas.drawRect(60,70,120,140, paint);//绘制实心的矩形 
    }
    public void run() {
     while(!Thread.currentThread().isInterrupted()){
      try{
       Thread.sleep(200);
      }catch(Exception e){
       e.printStackTrace();
       Thread.currentThread().interrupt();
      }
      postInvalidate();//使用postInvalidate可以直接在线程中更新界面
     }
    }
   }在View或SurfaceView中绘制图形后,需要在Activtiy中通过setContentView()来让其显示出来

第四部分 Canvas类和ShadeDrawable类
   Canvas方法:
    Canvas() 创建画布,可以用setBitmap()方法设置绘制具体画布
    Canvas(Bitmap bitmap) 以bitmap对象创建一个画布,则将内容都绘制在bitmap上,所以bitmap不得为null
    Canvas(GL gl) 绘制3D效果时使用,与OpenGL
    drawColor 设置画布背景色
    setBitmap 设置具体画布
    clipRect 设置显示区域,即设置裁剪区
    isOpaque 检测是否支持透明
    rotate 旋转画布 在游戏中我们需要对精灵旋转,缩放或其它操作就可以通过旋转画布来实现,但在旋转画布时会旋转画布上所以对象,而我们只需要旋转其中一个。这个时候
        我们就需要用save方法来锁定需要操作的对象,在操作后通过restore方法来解锁。(例子有此方法的运用)
    setViewport 设置画布中显示窗口
    skew 设置便宜量
    
    绘制几何图形的方法
    drawRect 绘制矩形
    drawCircle 绘制圆形
    drawOval 绘制椭圆
    drawLine 绘制直线
    drawPoint 绘制点
   
   public class CanvasView extends View implements Runnable{
    private Paint paint ;
    public ShapeDrawableView shapeDrawableView;
    public CanvasView(Context context) {
     super(context);
     paint = new Paint();
     shapeDrawableView= new ShapeDrawableView(context);//得到对象
     new Thread(this).start();
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     canvas.drawColor(Color.BLACK);//设置画布颜色
     paint.setAntiAlias(true);//取消抗锯齿效果
     //canvas.clipRect(20,20,80,80);//设置裁剪区域
  
     canvas.save();//锁定画布
     //canvas.rotate(45.0f);//旋转画布
     paint.setColor(Color.RED);//设置颜色及绘制矩形
     canvas.drawRect(new Rect(10,10,80,80), paint);
     canvas.restore();//解锁画布
 
     paint.setStyle(Paint.Style.STROKE);{//设置为空心画笔 
      Rect rect = new Rect();
       rect.left =85;
       rect.bottom=80;
       rect.right=150;
       rect.top = 10;
      paint.setColor(Color.BLUE);
      canvas.drawRect(rect, paint);//绘制矩形   
      canvas.drawCircle(60,60,50,paint);//绘制圆形
   
      RectF rectF = new RectF();//绘制椭圆
       rectF.bottom=80;
       rectF.left=160;
       rectF.right= 300;
       rectF.top = 10;
      canvas.drawOval(rectF, paint);
   
      Path path = new Path();//绘制多边形
       path.moveTo(10, 90);
       path.lineTo(80, 100);
       path.lineTo(70,150);
       path.lineTo(10, 200);
       path.close();//封闭多边形
      canvas.drawPath(path, paint);
   
      paint.setStrokeWidth(5);
      canvas.drawLine(50,50,300,200, paint);
     }
     paint.setStyle(Paint.Style.FILL);{//设置画笔为实心
      paint.setColor(Color.YELLOW);
      canvas.drawRect(20,250,300,300, paint);
     }  
     shapeDrawableView.DrawShape(canvas);//绘制另一View里的图形到本View中来
    }
    public void run() {
     while(!Thread.currentThread().isInterrupted()){
      try{
       Thread.sleep(200);
      }catch(Exception e){
       Thread.currentThread().interrupt();
      }
      postInvalidate();//直接在线程中更新
     }
    }
   }

   /**
   *Android中可以通过ShapeDrawable来绘制图像。可以通过getPaint方法得到Paint对象,
    setBounds 此方法可设置图形显示的区域
    通过ShapeDrawable的Draw方法将图形画到屏幕上
   */
   public class ShapeDrawableView extends View{
    ShapeDrawable shapeDrawable;
    Paint paint;
    public ShapeDrawableView(Context context) {
    super(context);
    }
    public void DrawShape(Canvas canvas){
     shapeDrawable = new ShapeDrawable();//------用ShapeDrawable绘图必须要实例化对象
     paint=shapeDrawable.getPaint();//得到画笔
     paint.setColor(Color.GREEN);//设置画笔颜色
     Rect bounds =new Rect(10,310,80,390);//绘制矩形
     shapeDrawable.setBounds(bounds);//------用ShapeDrawable绘图必须要使用SetBounds显示区域
     shapeDrawable.draw(canvas);//--------用ShapeDrawable绘图必须要使用draw()使图像显示到屏幕上 
     //另一种写法
     /* 实例化ShapeDrawable对象并说明是绘制一个椭圆 */
     shapeDrawable = new ShapeDrawable(new OvalShape());
     //得到画笔paint对象并设置其颜色
     shapeDrawable.getPaint().setColor(Color.GREEN);
     /* 设置图像显示的区域 */
     shapeDrawable.setBounds(70, 250, 150, 280);
     /* 绘制图像 */
     shapeDrawable.draw(canvas);
  
     //以下为绘制多边形
     Path path1 = new Path();
     /*设置多边形的点*/
     path1.moveTo(150+5, 80+80-50);
     path1.lineTo(150+45, 80+80-50);
     path1.lineTo(150+30, 80+120-50);
     path1.lineTo(150+20, 80+120-50);
     /* 使这些点构成封闭的多边形 */
     path1.close();
     //PathShape后面两个参数分别是宽度和高度
     shapeDrawable = new ShapeDrawable(new PathShape(path1,150,150));
     //得到画笔paint对象并设置其颜色
     shapeDrawable.getPaint().setColor(Color.BLUE);
     /* 设置图像显示的区域 */
     shapeDrawable.setBounds(100, 170, 200, 280);
     /* 绘制图像 */
     shapeDrawable.draw(canvas);
    }
   }

第五部分 字符串绘制
    Android中提供了drawText方法来绘制字符串,在绘制执法串之前需要设置画笔对象,包括字符串的尺寸,颜色等属性。使用FontMetrics来规划字体属性
    可以用getFontMetrics方法来获得系统字体的相关内容。
    setTextSize 设置字符串的尺寸
    setARGB 设置颜色
    getTextWidths 取得字符串宽度
    setFlags(Paint.ANTI_ALIAS_FLAG) 消除锯齿
    measureText 得到字符串宽度
      得到字符串高度可用:
      FontMetrics fontMetrics = paint.getFontMetrics();
      textselfHeight = (int)Math.ceil(fontMetrics.descent - fontMetrics.top)+2;//得到文字的高度
      textPageLineNum = textHeight/textselfHeight;//每一页的行数 = 绘制区域的高度/文字本身的高度

    下例实现了文本翻页,换行。
   
   * 实现文字自动换行
   * 自动翻页
   public class TextUtil{
    int  m_iTextPosX; //绘制的x点
    int  m_iTextPosY; //绘制的y点
    int  m_iTextWidth; //绘制宽度
    int  m_iTextHeight; //绘制高度
    int  m_iFontHeight; //字体高度
    int  m_ipageLineNum; //每一页显示的行数
    int  m_iTextBGColor; // 背景颜色
    int  m_iTextColor; // 字体颜色
    int  m_iAlpha;  //Alpha值
    int  m_iRealLine; // 字符串真实的行数
    int  m_iCurLine;  //当前行
    
    String m_strText;  
    Vector m_String;
    Paint m_paint;
    int  m_iTextSize;
    public TextUtil(){
     m_paint = new Paint();
     m_String = new Vector();
    }
    public TextUtil(String strText, int x, int y, int w, int h, int bgcolor, int txetcolor, int a, int iTextSize){
     m_paint = new Paint();
     m_String = new Vector();
     
     m_strText = strText;
     m_iTextPosX = x;
     m_iTextPosY = y;
     m_iTextWidth = w;
     m_iTextHeight = h;

     m_iTextBGColor = bgcolor;
     m_iTextColor = txetcolor;
     m_iTextSize = iTextSize;
     m_iAlpha = a;

    }
   /**
   * 初始化
   * @param strText 要显示的字符串
   * @param x   x
   * @param y   y
   * @param w   w
   * @param h   h 
   * @param bgcolor 背景颜色
   * @param txetcolor 文字的颜色
   * @param a   Alpha
   * @param iTextSize 字体大小
   */
    public void InitText(String strText, int x, int y, int w, int h, int bgcolor, int txetcolor, int a, int iTextSize){
     m_iCurLine = 0;
     m_ipageLineNum = 0;
     m_iRealLine = 0;
     m_strText = "";
     m_iTextPosX = 0;
     m_iTextPosY = 0;
     m_iTextWidth = 0;
     m_iTextHeight = 0;
     m_iTextBGColor = 0;
     m_iTextColor = 0;
     m_iTextSize = 0;
     m_iAlpha = 0;

     m_String.clear();

     SetText(strText);
     SetRect(x, y, w, h);
     SetBGColor(bgcolor);
     SetTextColor(txetcolor);
     SetFontSize(iTextSize);
     SetAlpha(a);

     SetPaint();
     GetTextIfon();
    }
   /**
   * 设置Alpha
   * @param a Alpha值
   */
    public void SetAlpha(int a){
     m_iAlpha = a;
    }
   /**
   * 对Paint属性的设置
   */
    public void SetPaint(){
     m_paint.setARGB(m_iAlpha, Color.red(m_iTextColor), Color.green(m_iTextColor), Color.blue(m_iTextColor));
     m_paint.setTextSize(m_iTextSize);
    }
   /**
   * 设置字体尺寸
   * @param iTextSize
   */
    public void SetFontSize(int iTextSize){
     m_iTextSize = iTextSize;
    }
   /**
   * 设置显示文本的区域
   * @param x
   * @param y
   * @param w
   * @param h
   */
    public void SetRect(int x, int y, int w, int h){
     m_iTextPosX = x;
     m_iTextPosY = y;
     m_iTextWidth = w;
     m_iTextHeight = h;
    }
   /**
   * 设置背景颜色
   * @param bgcolor
   */
    public void SetBGColor(int bgcolor){
     m_iTextBGColor = bgcolor;
    }
   /**
   * 设置字体颜色
   * @param txetcolor
   */
    public void SetTextColor(int txetcolor){
     m_iTextColor = txetcolor;
    }
   /**
   * 色绘制要显示的字符串
   * @param strText
   */
    public void SetText(String strText){
     m_strText = strText;
    }
   /**
   * 得到字符串的信息
   * 包括:行数、页数等信息
   * 内部调用
   */
    public void GetTextIfon(){
     char ch;
     int w = 0;
     int istart = 0;
     FontMetrics fm = m_paint.getFontMetrics(); 
     m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + 2;
     m_ipageLineNum = m_iTextHeight / m_iFontHeight;
      for (int i = 0; i < m_strText.length(); i++){
       ch = m_strText.charAt(i);
       float[] widths = new float[1];
       String srt = String.valueOf(ch);
       m_paint.getTextWidths(srt, widths);
        if (ch == '\n'){
         m_iRealLine++;
         m_String.addElement(m_strText.substring(istart, i));
         istart = i + 1;
         w = 0;
        }else{
         w += (int) (Math.ceil(widths[0]));
         if (w > m_iTextWidth){
          m_iRealLine++;
          m_String.addElement(m_strText.substring(istart, i));
          istart = i;
          i--;
          w = 0;
         }else{
          if (i == (m_strText.length() - 1)){
           m_iRealLine++;
           m_String.addElement(m_strText.substring(istart, m_strText.length()));
          }
         }
        }
      }
    }
   /**
   * 绘制字符串
   * @param canvas
   */
    public void DrawText(Canvas canvas){
     for (int i = m_iCurLine, j = 0; i < m_iRealLine; i++, j++){
      if (j > m_ipageLineNum){
       break;
      }
      canvas.drawText((String) (m_String.elementAt(i)), m_iTextPosX, m_iTextPosY + m_iFontHeight * j, m_paint);
     }
    }
   /**
   * 翻页等按键处理
   * @param keyCode
   * @param event
   * @return
   */
    public boolean KeyDown(int keyCode, KeyEvent event){
     if (keyCode == KeyEvent.KEYCODE_DPAD_UP){
      if (m_iCurLine > 0){
       m_iCurLine--;
      }
     }else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN){
      if ((m_iCurLine + m_ipageLineNum) < (m_iRealLine - 1)){
       m_iCurLine++;
      }
     }
     return false;
    }
   }

   public class GameView extends View implements Runnable{
    /* 声明Paint对象 */
    private Paint mPaint = null;
    private int   mICount = 0; 
    /* 声明TextUtil对象 */
    private TextUtil mTextUtil = null;
    public GameView(Context context){
     super(context);
     /* 构建对象 */
     mPaint = new Paint(); 
     String string = "测试自动换行\n\n设置文字自动换行abcdefgh\niklmnopqrst换行123347465\n43756245Android\n设置文字自动换行abcdefgh\n
        iklmnopqrst换行123347465\n43756245Android"; 
     /* 实例化TextUtil */
     mTextUtil = new TextUtil(string,5,50,300,80,0x0,0xffffff,255,16);
     /* 初始化TextUtil */
     mTextUtil.InitText(string,5,150,300,80,0x0,0xffffff,255,16);
     /* 开启线程  */
     new Thread(this).start();
    } 
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     /* 设置背景颜色 */
     canvas.drawColor(Color.BLACK);
     mPaint.setAntiAlias(true);
     if ( mICount < 100 ){
      mICount++;
     }
     mPaint.setColor(Color.RED);
     canvas.drawText("装在进度:"+mICount+"%......", 10, 20, mPaint);
     /* 绘制TextUtil:实现自动换行 */
     mTextUtil.DrawText(canvas);
    }
    // 触笔事件
    public boolean onTouchEvent(MotionEvent event){
     return true;
    }
    // 按键按下事件
    public boolean onKeyDown(int keyCode, KeyEvent event){
     return mTextUtil.KeyDown(keyCode, event);
    }
    // 按键弹起事件
    public boolean onKeyUp(int keyCode, KeyEvent event){
     return false;
    }
    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event){
     return true;
    } 
   /**
   * 线程处理
   */
    public void run(){
     while (!Thread.currentThread().isInterrupted()){
      try{
       Thread.sleep(100);
      }catch (InterruptedException e){
       Thread.currentThread().interrupt();
      }
       //使用postInvalidate可以直接在线程中更新界面
       postInvalidate();
     }
    }
   }
   
   public class Activity01 extends Activity{
    private GameView mGameView = null;

    public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     mGameView = new GameView(this);
     setContentView(mGameView);
    }
    // 按键弹起事件
    public boolean onKeyUp(int keyCode, KeyEvent event){
     return super.onKeyUp(keyCode, event);
    }
    // 按键按下事件
    public boolean onKeyDown(int keyCode, KeyEvent event){
     mGameView.onKeyDown(keyCode, event);
     return true;
    }
   }
   
第六部分 图像的绘制 旋转 缩放
    1.((BitmapDrawable) getResource().getDrawable(资源索引)).getBitmap() 加载资源
    2.canvas.drawBitmap(bitmap,x,y,null);将bitmap绘制在屏幕的(x,y)位置
    3.getHeight() ,getWidth() 获得图片的高度好宽度
    4.Android中通过Matrix旋转图片。Matrix没有结果体,它必须被实例化,可通过reset方法或set方法来实现。
     setRotate方法来设置旋转角度
     createBitmap 创建一个经过旋转等处理的Bitmap对象
    5.Matrix的postScale(x,y)方法来设置缩放的倍数 分别在x,y方法缩放的倍数。

   public class Draw_Bitmap extends Activity{
    public DrawBitmap drawBitmap;
    public void onCreate(Bundle savedInstanceState){
     drawBitmap = new DrawBitmap(this);
     super.onCreate(savedInstanceState);
     setContentView(drawBitmap);
    }
    public boolean onKeyDown(int keyCode,KeyEvent event){
     if(drawBitmap == null){
      return false;
     }else if(keyCode ==KeyEvent.KEYCODE_BACK){
      this.finish();
      return true;
     }
     return drawBitmap.onKeyDown(keyCode, event); 
    }
   }
 
   public class DrawBitmap extends View implements Runnable{
    private static Paint paint1=null;
    public static Bitmap dog1=null;
    public Bitmap tb1=null;
    public int dog1width = 0;
    public int dog1height = 0;
    public float rotate=0.0f;
    public float scale = 1.0f;
 
    Matrix matrix = new Matrix();//构建Matrix对象 Matrix用于旋转图片

    public DrawBitmap(Context context) {
     super(context);
     paint1 = new Paint();
     //从资源中装载图片
     dog1 = ((BitmapDrawable)getResources().getDrawable(R.drawable.dog)).getBitmap();
     tb1 = ((BitmapDrawable)getResources().getDrawable(R.drawable.tb)).getBitmap();
  
     dog1width = dog1.getWidth();//得到图像的宽度
     dog1height =dog1.getHeight();//得到图像的高度
  
     new Thread(this).start();//创建,开启线程
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     canvas.drawColor(Color.BLUE);
     canvas.drawBitmap(dog1,10,240,paint1);
  
     matrix.reset();//重置matrix得到Matrix的方法体
     matrix.setRotate(rotate);//设置旋转
     matrix.postScale(scale, scale);//设置缩放分别为(x,y)方法的缩放
     Bitmap dog1rotate = Bitmap.createBitmap(dog1,0,0,dog1width,dog1height,matrix,true);//按Matrix的旋转构建新的Bitmap
     DrawBitmap.drawImage(canvas,dog1rotate,130,240);//绘制旋转后的图片
  
     dog1rotate= null;//这里难道是释放资源
  
     DrawBitmap.drawImage(canvas,dog1,0,0);//在屏幕的(0,0)处绘制图片
     DrawBitmap.drawImage2(canvas,tb1,10,dog1.getHeight(),142,100,150,178);//在指定位置按指定的裁决区域进行绘制
    }
   /**
   * i---屏幕上的x坐标
   * height---屏幕上的y坐标
   * j---要绘制图片的宽度
   *k---要绘制图片的高度
   *l---图片上的x坐标
   *m---图片上的Y坐标
   */
    private static void drawImage2(Canvas canvas, Bitmap tb12, int i,
              int height, int j, int k, int l, int m) {
     Rect rect1 = new Rect();//图片上裁剪区域
      rect1.left = l;
      rect1.top =m;
      rect1.right=l+j;
      rect1.bottom = m+k;
  
     Rect rect2 = new Rect();//屏幕上的裁剪区域
      rect2.left = i;
      rect2.top = height;
      rect2.right =i+j;
      rect2.bottom = height+k;
     canvas.drawBitmap(tb12, rect1,rect2, null);
    }
    private static void drawImage(Canvas canvas, Bitmap dog12, int i, int j){
     canvas.drawBitmap(dog12,i,j,null);
    } 
    public boolean onKeyDown(int keyCode,KeyEvent event){
     if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
      rotate+=10;
     }else if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
      rotate--;
     }else if(keyCode == KeyEvent.KEYCODE_DPAD_DOWN){
      if(scale>0.3){//注意:scale必须大于0,否则会报错
       scale-=0.1;
      }
     }else if(keyCode == KeyEvent.KEYCODE_DPAD_UP){
      if(scale<2.0){
       scale+=0.1;
      }
     }
     return true; 
    }
    public boolean onKeyUp(int keyCode,KeyEvent event){
     return false;
    }
    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event){
     return true;
    }
    @Override
    public void run() {
     while(!Thread.currentThread().isInterrupted()){
      try{
       Thread.sleep(100);
      }catch(Exception e){
       Thread.currentThread().interrupt();
      }
       postInvalidate();
     }
    }
   }


第七部分 图像像素的操作
   Android中Bitmap提供了操作像素的方法,可通过getPixels方法获得图像像素并放到一个数组中去。我们处理这个数组就可以了,最后通过setPixels设置这个像素数组到Bitmap中去。
   Android中,每一个图像像素通过4字节整数来展现:最高位字节用作Alpha通道。即用来实现透明与不透明控制,255代表完全透明,0为完全不透明;接下来的一个字节是Red红色通道。
   255代表完全是红色。依次类推,接下来的两个字节相应地实现绿色和蓝色通道。
    下例为通过图像像素的操作来模拟水纹效果。
    
   public class GameView extends View implements Runnable{
    int BACKWIDTH;
    int BACKHEIGHT;
    short[] buf2;
    short[] buf1;
    int[] Bitmap2;
    int[] Bitmap1; 
   public GameView(Context context){
    super(context); 
    Bitmap  image = BitmapFactory.decodeResource(this.getResources(),R.drawable.qq);//装载图片
    BACKWIDTH = image.getWidth();
    BACKHEIGHT = image.getHeight();
     
    buf2 = new short[BACKWIDTH * BACKHEIGHT];
    buf1 = new short[BACKWIDTH * BACKHEIGHT];
    Bitmap2 = new int[BACKWIDTH * BACKHEIGHT];
    Bitmap1 = new int[BACKWIDTH * BACKHEIGHT];

    image.getPixels(Bitmap1, 0, BACKWIDTH, 0, 0, BACKWIDTH, BACKHEIGHT);//加载图片的像素到数组中  
    new Thread(this).start();
   }
   public void DropStone(
    int x,    // x坐标
    int y,    // y坐标
    int stonesize,  // 波源半径
    int stoneweight){ // 波源能量   
    for (int posx = x - stonesize; posx < x + stonesize; posx++)
     for (int posy = y - stonesize; posy < y + stonesize; posy++)
      if ((posx - x) * (posx - x) + (posy - y) * (posy - y) < stonesize * stonesize)
      buf1[BACKWIDTH * posy + posx] = (short) -stoneweight;
   }  
   public void RippleSpread(){
    for (int i = BACKWIDTH; i < BACKWIDTH * BACKHEIGHT - BACKWIDTH; i++){   
     buf2[i] = (short) (((buf1[i - 1] + buf1[i + 1] + buf1[i - BACKWIDTH] + buf1[i + BACKWIDTH]) >> 1) - buf2[i]);// 波能扩散  
     buf2[i] -= buf2[i] >> 5;// 波能衰减
    }
    // 交换波能数据缓冲区
    short[] ptmp = buf1;
    buf1 = buf2;
    buf2 = ptmp;
   }
   public void render(){//渲染你水纹效果 
    int xoff, yoff;
    int k = BACKWIDTH;
    for (int i = 1; i < BACKHEIGHT - 1; i++){
     for (int j = 0; j < BACKWIDTH; j++){
      // 计算偏移量
      xoff = buf1[k - 1] - buf1[k + 1];
      yoff = buf1[k - BACKWIDTH] - buf1[k + BACKWIDTH];
      // 判断坐标是否在窗口范围内
      if ((i + yoff) < 0){
       k++;
       continue;
      }
      if ((i + yoff) > BACKHEIGHT){
       k++;
       continue;
      }
      if ((j + xoff) < 0){
       k++;
       continue;
      }
      if ((j + xoff) > BACKWIDTH){
       k++;
       continue;
      }
      // 计算出偏移象素和原始象素的内存地址偏移量
      int pos1, pos2;
      pos1 = BACKWIDTH * (i + yoff) + (j + xoff);
      pos2 = BACKWIDTH * i + j;
      Bitmap2[pos2++] = Bitmap1[pos1++];
      k++;
     }
    }
   } 
   public void onDraw(Canvas canvas){
    super.onDraw(canvas); 
    canvas.drawBitmap(Bitmap2, 0, BACKWIDTH, 0, 0, BACKWIDTH, BACKHEIGHT, false, null);//绘制经过处理的图片效果
   } 
   public boolean onTouchEvent(MotionEvent event){// 触笔事件  
    return true;
   }
   public boolean onKeyDown(int keyCode, KeyEvent event){// 按键按下事件
    return true;
   }
   public boolean onKeyUp(int keyCode, KeyEvent event){// 按键弹起事件
    DropStone(BACKWIDTH/2, BACKHEIGHT/2, 10, 30);
    return false;
   }
   public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event){
    return true;
   }
   public void run(){//线程处理
    while (!Thread.currentThread().isInterrupted()){
     try{
      Thread.sleep(50);
     }catch (InterruptedException e){
      Thread.currentThread().interrupt();
     }
      RippleSpread();
      render();
     //使用postInvalidate可以直接在线程中更新界面
     postInvalidate();
    }
   }
   }


第八部分 Shader类 图片的渲染
   /**
   * 所谓的渲染就是对画笔的设置 本人是这样理解的。Shader类的使用,都需要先构建Shader对象,然后通过Paint的setShader方法来设置渲染对象,然后在绘制时使用Paint
    对象。当然用不同的渲染需要构建不同的对象(即相当于创建不同的画笔)。
   */
   public class Shader01 extends View{
    Bitmap qq2 = null;
    int qq2width = 0;
    int qq2height = 0;
    Paint paint = null;
 
    Shader bitmapShaper = null;//Bitmap渲染
    Shader linearGradient = null;//线性渲染
    Shader radialGradient = null;//环形渲染
    Shader sweepGradient = null;//梯度渲染
    Shader composeShaper = null;//混合渲染
 
    ShapeDrawable shapeDrawable = null;
 
    public Shader01(Context context) {
     super(context);
     qq2 = ((BitmapDrawable) getResources().getDrawable(R.drawable.qq)).getBitmap();//装载资源
  
     qq2width = qq2.getWidth();//得到图片的宽度
     qq2height = qq2.getHeight();//得到图片的高度
  
     //创建BitmapShader对象
     bitmapShaper = new BitmapShader(qq2,Shader.TileMode.REPEAT,Shader.TileMode.MIRROR);//要想裁剪需要使用BitmapShader类来裁剪,得到图片的宽度和高度
  
     //创建linearGradient对象并设置变化的颜色数组
     linearGradient = new LinearGradient(10, 0, 50, 100,
        new int []{Color.RED,Color.YELLOW,Color.BLACK}, null, Shader.TileMode.MIRROR);
  
     //混合渲染
     composeShaper =new ComposeShader(linearGradient, bitmapShaper, PorterDuff.Mode.DARKEN);//也可选用其他的混合
  
     //环形渲染
     radialGradient = new RadialGradient(50, 200, 50,
        new int[]{Color.GREEN,Color.RED,Color.BLUE}, null, Shader.TileMode.REPEAT);
  
     //梯度渲染
     sweepGradient = new SweepGradient(30, 30, new int[]{Color.GREEN,Color.RED,Color.BLUE}, null);
     paint = new Paint();//创建画笔  
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     shapeDrawable = new ShapeDrawable(new OvalShape());//设置绘制椭圆
     shapeDrawable.getPaint().setShader(bitmapShaper);//设置要绘制的椭圆形的图片
     shapeDrawable.setBounds(0,0,qq2width,qq2height);//设置要显示的区域
     shapeDrawable.draw(canvas);//绘制图片
  
     paint.setShader(linearGradient);//绘制线性渲染
     canvas.drawRect(200,0,320,50, paint);
  
     paint.setShader(composeShaper);//绘制混合渲染
     canvas.drawRect(200,55,320,105, paint);
  
     paint.setShader(radialGradient);//绘制环形渲染
     canvas.drawRect(200,200,320,250, paint);
  
     paint.setShader(sweepGradient);//绘制梯度渲染
     canvas.drawRect(200,110,320,160, paint); 
    }

   }
   =================================================================================================================================================
第九部分 双缓冲技术
    原理:当一个动画争先显示时,程序又在改变它,前面的还没画完,程序又请求重新绘制,这时就会出现闪屏。为避免这种情况,可以使用双缓冲技术,将要处理好的的图片
   在内存中处理好之后,再将其显示到屏幕上。Android中SurfaceView类本身就是一个双缓冲机制,所以游戏开发中用SurfaceView用得更多,效率也更高。下例是针对View类实现
   双缓冲技术的例子。
    
   public class BufferView extends View implements Runnable{-----------???
    Bitmap bitmap1= null;
    Bitmap bufferBitmap = null;//创建缓冲区
 
    Canvas canvas1 = null;
    Paint paint = null;

    public BufferView(Context context) {
     super(context);
     bitmap1 = ((BitmapDrawable)getResources().getDrawable(R.drawable.qq)).getBitmap();//装载资源
  
     bufferBitmap = Bitmap.createBitmap(320,480,Config.ARGB_8888);//创建屏幕大小的缓冲区
  
     canvas1 = new Canvas();//创建画布(程序中出现了两块画布)
     paint = new Paint();
  
     canvas1.setBitmap(bufferBitmap);//将内容绘制在bufferBitmap缓冲区上,可理解为将缓冲区作为画布。
  
     canvas1.drawBitmap(bitmap1, 0,0, paint);//将图片绘制到缓冲区上
  
     new Thread(this).start();
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     canvas.drawBitmap(bufferBitmap, 0,0, paint);//将bufferBitmap缓冲区上画布绘制到屏幕上去
    }
    @Override
    public void run() {
     while(!Thread.currentThread().isInterrupted()){
      try{
       Thread.sleep(200);
      }catch(Exception e){
       Thread.currentThread().interrupt();
      }
      postInvalidate();
     }
    }
   }

   ================================================================================================================================================= 
第十部分  全屏显示及获取屏幕属性
    如果想像G1游戏那样,当我们把手机屏幕横放时,应用程序会自动变为横屏模式。其实可以通过下面两个方法实现这个功能。
     法一:双击AndroidManifest.xml文件,选择Application选项卡,选中Activity类,再找到Screen orientation选项 ,选择 senor 最后保存即可。在真机上就能看到效果
     法二:在AndroidManifest.xml文件中设计如下中加入android:screenOrientation="senor"即可。如下:
       <activity android:name=".GameActivity"
          android:label="@string/app_name"
          android:screenOrientation="senor">
   
   public class FullScreen extends Activity{
    public TextView textView_FullScreen;//定义一个TextView来显示屏幕属性
    public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
  
     requestWindowFeature(Window.FEATURE_NO_TITLE);//通过requestWindowFeature方法来设置为无标题栏
     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
              WindowManager.LayoutParams.FLAG_FULLSCREEN);//通过setFlags方法设置为全屏模式
     setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//通过setRequestedOrientation方法来设置为横屏
     setContentView(R.layout.fullscreen);
     
     textView_FullScreen = (TextView)this.findViewById(R.id.textView_FullScreen);//得到TextView对象
     
     DisplayMetrics displayMetrics = new DisplayMetrics();//定义DisplayMetrics对象,DisplayMetrics定义了屏幕的一些属性
  
     getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);//通过getMetrics方法来取得窗口属性
  
     int screenWidth = displayMetrics.widthPixels;//得到窗口宽度
     int screenHeight = displayMetrics.heightPixels;//得到窗口高度
  
     textView_FullScreen.setText("屏幕宽度:"+screenWidth+"\n屏幕高度:"+screenHeight);
    }
   }

第十一部分  Tween动画
   第一种方法 在代码中设计
   public class AnimationView extends View{
    public Animation animationAlpha = null;
    public Animation animationScale = null;
    public Animation animationTranslate = null;
    public Animation animationRotate = null;
 
    Bitmap bitmap1 = null;

    public AnimationView(Context context) {
     super(context);
     bitmap1 = ((BitmapDrawable)getResources().getDrawable(R.drawable.dog)).getBitmap();//加载资源
    }
    public void onDraw(Canvas canvas){
     canvas.drawBitmap(bitmap1, 50,100, null);
    }
    public boolean onKeyUp(int keyCode,KeyEvent event){
     switch(keyCode){
      /*
      * Alpha透明度动画效果。其属性设置格式为:
      * AlphaAnimation(float fromAlpha,float toAlpha)
      * fromAlpha---为动画起始时透明度
      * toAlpha---动画结束时透明度(0.0表示完全透明,1.0表示完全不透明)
      *
      * setDuration(long durationMillis);设置动画显示的时间 单位为毫秒
      * startAnimation(Animation animation);开始播放动画
      */
     case KeyEvent.KEYCODE_DPAD_UP:
      animationAlpha = new AlphaAnimation(0.0f, 1.0f);//创建Alpha动画
      animationAlpha.setDuration(3000);//动画持续时间
      this.startAnimation(animationAlpha);//开始播放动画
      break;
      /*
      * Scale伸缩动画效果.。其属性设置如下:
      * ScaleAnimation(fromX, toX, fromY, toY, pivotXType, pivotXValue, pivotYType, pivotYValue)
      * fromX,toX 为起始和结束时x坐标上的伸缩尺寸
      * fromY,toY 为起始和结束时y坐标上的伸缩尺寸
      * pivotXType,pivotYType 分别为x,y的伸缩模式
      * pivotXVale,pivotYVale 分别为伸缩动画相对于x,y的坐标开始位置
      */
     case KeyEvent.KEYCODE_DPAD_DOWN:
      animationScale = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF,
            0.5f, Animation.RELATIVE_TO_SELF, 0.5f);//创建Scale动画
      animationScale.setDuration(500);//动画持续的时间
      this.startAnimation(animationScale);//开始播放动画
      /*
      * Translate移动动画效果。其属性设置如下:
      * TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta)
      * fromXDelta ,fromYDelta 分别为起始x,y坐标
      * toXDelta,toYDelta 分别为终点时x,y坐标
      */
     case KeyEvent.KEYCODE_DPAD_LEFT:
      animationTranslate = new TranslateAnimation(10, 100, 10, 100);//创建Translate动画
      animationTranslate.setDuration(1000);//动画持续时间
      this.startAnimation(animationTranslate);//开始播放动画
      break;
      /*
      * Rotate旋转动画效果
      * RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue)
      * fromDegrees 开始角度
      * toDegrees 结束角度
      * pivotXValue , pivotYValue 伸缩动画相对于x,y的坐标坐标开始位置
      * pivotXType,pivotYType 分别为x,y的伸缩模式
      */
     case KeyEvent.KEYCODE_DPAD_RIGHT:
      animationRotate = new RotateAnimation(0.0f, 360f, Animation.RELATIVE_TO_SELF,
              0.5f, Animation.RELATIVE_TO_SELF, 0.5f);//创建Rotate动画
      animationRotate.setDuration(1000);//动画持续时间
      this.startAnimation(animationRotate);//动画播放
     }
      return true; 
    }
   }  需在Activity种实例化
   -------------------------------------------------------------------------------------------------------
   第二种方法 xml设计
   aipha.xml
    <?xml version="1.0" encoding="utf-8"?>//也可将这四个xml放在一起 为没一个设置一个id
    <set xmlns:android="
http://schemas.android.com/apk/res/android" >
     <alpha
      android:fromAlpha="0.1"
      android:toAlpha="1.0"
      android:duration="2000"
     />
    </set>
   
   rotate.xml
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="
http://schemas.android.com/apk/res/android">      
     <rotate
      android:interpolator="@android:anim/accelerate_decelerate_interpolator"     
      android:fromDegrees="0"
      android:toDegrees="+360"              
      android:pivotX="50%"
      android:pivotY="50%"             
      android:duration="1000" />
    </set>

   scale.xml
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="
http://schemas.android.com/apk/res/android">
     <scale
      android:interpolator="@android:anim/accelerate_decelerate_interpolator"        
      android:fromXScale="0.0"
      android:toXScale="1.0"       
      android:fromYScale="0.0"
      android:toYScale="1.0"        
      android:pivotX="50%"
      android:pivotY="50%"         
      android:fillAfter="false"
      android:duration="500" />
    </set>

   translate.xml
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="
http://schemas.android.com/apk/res/android">
     <translate
      android:fromXDelta="10"
      android:toXDelta="100"
      android:fromYDelta="10"
      android:toYDelta="100"
      android:duration="1000"
     />
    </set>
   
   public class GameView extends View{
    private Animation mAnimationAlpha  = null;//定义Alpha动画
    private Animation mAnimationScale  = null;//定义Scale动画
    private Animation mAnimationTranslate = null;//定义Translate动画
    private Animation mAnimationRotate = null;//定义Rotate动画
    
    Bitmap    mBitQQ    = null;//定义Bitmap对象
    Context mContext = null;
    public GameView(Context context){
     super(context); 
     mContext = context;
  
     mBitQQ = ((BitmapDrawable) getResources().getDrawable(R.drawable.qq)).getBitmap();//装载资源
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     canvas.drawBitmap(mBitQQ, 0, 0, null);//绘制图片
    } 
    public boolean onKeyUp(int keyCode, KeyEvent event){
     switch ( keyCode ){
      case KeyEvent.KEYCODE_DPAD_UP:
       mAnimationAlpha = AnimationUtils.loadAnimation(mContext,R.layout.alpha);//装载动画布局
       this.startAnimation(mAnimationAlpha);//开始播放动画
       break;
      case KeyEvent.KEYCODE_DPAD_DOWN:
       mAnimationScale = AnimationUtils.loadAnimation(mContext,R.layout.scale);//装载动画布局
       this.startAnimation(mAnimationScale);//开始播放动画
       break;
      case KeyEvent.KEYCODE_DPAD_LEFT:
       mAnimationTranslate = AnimationUtils.loadAnimation(mContext,R.layout.translate);//装载动画布局
       this.startAnimation(mAnimationTranslate);//开始播放动画
       break;
      case KeyEvent.KEYCODE_DPAD_RIGHT:
       mAnimationRotate = AnimationUtils.loadAnimation(mContext,R.layout.rotate);//装载动画布局
       this.startAnimation(mAnimationRotate);//开始播放动画
       break;
     }
     return true;
    }
   }


   ===================================================================================================================================
   Framed动画
   第一种方法 在代码中设计
   public class GameView extends View{    
    private AnimationDrawable animationDrawable = null;//定义AnimationDrawable装载动画
    Context      mContext  = null;
    Drawable    mBitAnimation  = null;//定义一个Drawable对象
    public GameView(Context context){
     super(context);
     mContext = context; 
     animationDrawable = new AnimationDrawable();//实例化AnimationDrawable对象 
     
     for (int i = 1; i <= 15; i++){//利用循环装载所有名字类似的资源(图片命名时是有规律的 所以才能用此循环)
      int id = getResources().getIdentifier("a" + i, "drawable", mContext.getPackageName());------------------------需要深入
      mBitAnimation = getResources().getDrawable(id);
   
      animationDrawable.addFrame(mBitAnimation, 500);//通过addFrame方法把每一帧添加进去,每一帧显示的时间为500毫秒
     }
     animationDrawable.setOneShot( false );//利用setOneShot方法设置播放模式是否循环false表示循环而true表示不循环

     this.setBackgroundDrawable(animationDrawable);// 加载本类将要显示这个动画
    } 
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);  
    }
    public boolean onKeyUp(int keyCode, KeyEvent event){
     switch ( keyCode ){
      case KeyEvent.KEYCODE_DPAD_UP:  
      animationDrawable.start();//最后通过start方法播放动画
       break;
     }
     return true;
    }
   }     要想显示Frame动画,还要在Activity中添加GameView对象
   ------------------------------------------------------------------------------
   第二种方法:在XML文件中的设计
   frameanimation.xml
    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="
http://schemas.android.com/apk/res/android"
          android:oneshot="false">
     <item android:drawable="@drawable/a1" android:duration="500" />
     <item android:drawable="@drawable/a2" android:duration="500" />
     <item android:drawable="@drawable/a3" android:duration="500" />
     <item android:drawable="@drawable/a4" android:duration="500" />
     <item android:drawable="@drawable/a5" android:duration="500" />
     <item android:drawable="@drawable/a6" android:duration="500" />
     <item android:drawable="@drawable/a7" android:duration="500" />
     <item android:drawable="@drawable/a8" android:duration="500" />
     <item android:drawable="@drawable/a9" android:duration="500" />
     <item android:drawable="@drawable/a10" android:duration="500" />
     <item android:drawable="@drawable/a11" android:duration="500" />
     <item android:drawable="@drawable/a12" android:duration="500" />
    </animation-list>

    public class GameView extends View{
     private AnimationDrawable frameAnimation = null;
     Context      mContext  = null;
     public GameView(Context context){
      super(context);  
      mContext = context;
      ImageView img = new ImageView(mContext);//定义一个ImageView用来显示动画
  
      img.setBackgroundResource(R.anim.frameanimation);//装载动画布局文件  
  
      frameAnimation = (AnimationDrawable) img.getBackground();//构建动画
  
      frameAnimation.setOneShot( false );  //设置是否循环
  
      this.setBackgroundDrawable(frameAnimation);//设置该类显示的动画
     }
 
     public void onDraw(Canvas canvas){
      super.onDraw(canvas);
     }
 
     public boolean onKeyUp(int keyCode, KeyEvent event){
      switch ( keyCode ){
       case KeyEvent.KEYCODE_DPAD_UP: 
        frameAnimation.start();//开始播放动画
        break;
      }
      return true;
     }
    }  还许要在Acitivity类中实例化GameView对象才能显示。


   ===================================================================================================================================================
   GIF动画播放
   其原理:首先需要对GIF动画图像进行解码,然后将GIF中的每一帧分别提取出来保存到一个容器中,然后根据需要绘制每一帧,这样就可以轻松地实现GIF动画的播放了。
   下面有个例子,可以在工作中直接使用。
   
   public class GifDecoder{
    private int     E0;
    private int     E1[];
    private int     E2;
    private int     E6;
    private boolean    E7;
    private int     E8[];
    private int     width;
    private int     height;
    private int     ED;
    private boolean    EE;
    private boolean    EF;
    private int     F0[];
    private int     F1;
    private boolean    F2;
    private int     F3;
    private long    F4;
    private int     F5;
    private static final int F6[] = { 8, 8, 4, 2 };
    private static final int F8[] = { 0, 4, 2, 1 };
    int       curFrame;
    int       poolsize;
    int       FA;
    byte      C2[];
    int       FB;
    int       FC;
    int       FD;
    public GifDecoder(byte abyte0[]){
     E0 = -1;
     E1 = new int[280];
     E2 = -1;
     E6 = 0;
     E7 = false;
     E8 = null;
     width = 0;
     height = 0;
     ED = 0;
     EE = false;
     EF = false;
     F0 = null;
     F1 = 0;
     F5 = 0;
     curFrame = 0;
     C2 = abyte0;
     poolsize = C2.length;
     FA = 0;
    }
    public boolean moreFrames(){
     return poolsize - FA >= 16;
    }
    public void nextFrame(){
     curFrame++;
    }
    public Bitmap decodeImage(){
     return decodeImage(curFrame);
    }
    public Bitmap decodeImage(int i){
     if (i <= E0){
     return null;
     }
     if (E0 < 0){
      if (!E3()){
       return null;
      }
      if (!E4()){
       return null;
      }
     }
     do{
      if (!E9(1)){
       return null;
      }
      int j = E1[0];
      if (j == 59){
       return null;
      }
      if (j == 33){
       if (!E7()){
       return null;
       }
      }
      else if (j == 44){
       if (!E5()){
        return null;
       }
       Bitmap image = createImage();
       E0++;
       if (E0 < i){
        image = null;
       }else{
        return image;
       }
      }
     }
     while (true);
    }
    public void clear(){
     C2 = null;
     E1 = null;
     E8 = null;
     F0 = null;
    }
    private Bitmap createImage(){
     int i = width;
     int j = height;
     int j1 = 0;
     int k1 = 0;
     int ai[] = new int[4096];
     int ai1[] = new int[4096];
     int ai2[] = new int[8192];
     if (!E9(1)){
      return null;
     }
     int k = E1[0];
     int[] image = new int[width * height];
     int ai3[] = E8;
     if (EE){
      ai3 = F0;
     }
     if (E2 >= 0){
      ai3[E2] = 0xffffff;
     }
     int l2 = 1 << k;
     int j3 = l2 + 1;
     int k2 = k + 1;
     int l3 = l2 + 2;
     int k3 = -1;
     int j4 = -1;
     for (int l1 = 0; l1 < l2; l1++){
      ai1[l1] = l1;
     }
     int j2 = 0;
     E2();
     j1 = 0;
     label0: for (int i2 = 0; i2 < j; i2++){
      int i1 = 0;
      do{
       if (i1 >= i){
        break;
       }
       if (j2 == 0){
        int i4 = E1(k2);
        if (i4 < 0){
         return Bitmap.createBitmap(image, width, height, Config.RGB_565);
        }
        if (i4 > l3 || i4 == j3){
         return Bitmap.createBitmap(image, width, height, Config.RGB_565);
        }
        if (i4 == l2){
         k2 = k + 1;
         l3 = l2 + 2;
         k3 = -1;
         continue;
        }
        if (k3 == -1){
         ai2[j2++] = ai1[i4];
         k3 = i4;
         j4 = i4;
         continue;
        }
        int i3 = i4;
        if (i4 == l3){
         ai2[j2++] = j4;
         i4 = k3;
        }
        for (; i4 > l2; i4 = ai[i4]){
         ai2[j2++] = ai1[i4];
        }
        j4 = ai1[i4];
        if (l3 >= 4096){
         return Bitmap.createBitmap(image, width, height, Config.RGB_565);
        }
        ai2[j2++] = j4;
        ai[l3] = k3;
        ai1[l3] = j4;
        if (++l3 >= 1 << k2 && l3 < 4096){
         k2++;
        }
        k3 = i3;
       }
       int l = ai2[--j2];
       if (l < 0){
        return Bitmap.createBitmap(image, width, height, Config.RGB_565);
       }
       if (i1 == 0){
        FC = 0;
        FB = ai3[l];
        FD = 0;
       }else if (FB != ai3[l]){
        for (int mm = FD; mm <= FD + FC; mm++){
         image[j1 * width + mm] = FB;
         }
        FC = 0;
        FB = ai3[l];
        FD = i1;
        if (i1 == i - 1){
         image[j1 * width + i1] = ai3[l];
        }
       }else{
        FC++;
        if (i1 == i - 1){
         for (int mm = FD; mm <= FD + FC; mm++){
          image[j1 * width + mm] = FB;
         }
        }
       }
        i1++;
      }
      while (true);
       if (EF){
        j1 += F6[k1];
        do{
         if (j1 < j){
          continue label0;
         }
         if (++k1 > 3){
          return Bitmap.createBitmap(image, width, height, Config.RGB_565);
         }
         j1 = F8[k1];
        }
        while (true);
       }
       j1++;
     }
      return Bitmap.createBitmap(image, width, height, Config.RGB_565);
    }
    private int E1(int i){
     while (F5 < i){
      if (F2){
       return -1;
      }
      if (F1 == 0){
       F1 = E8();
       F3 = 0;
       if (F1 <= 0){
        F2 = true;
        break;
       }
      }
      F4 += E1[F3] << F5;
      F3++;
      F5 += 8;
      F1--;
     }
     int j = (int) F4 & (1 << i) - 1;
     F4 >>= i;
     F5 -= i;
     return j;
    }
    private void E2(){
     F5 = 0;
     F1 = 0;
     F4 = 0L;
     F2 = false;
     F3 = -1;
    }
    private boolean E3(){
     if (!E9(6)){
      return false;
     }
     return E1[0] == 71 && E1[1] == 73 && E1[2] == 70 && E1[3] == 56 && (E1[4] == 55 || E1[4] == 57) && E1[5] == 97;
    }
    private boolean E4(){
     if (!E9(7)){
      return false;
     }
     int i = E1[4];
     E6 = 2 << (i & 7);
     E7 = EB(i, 128);
     E8 = null;
     return !E7 || E6(E6, true);
    }
    private boolean E5(){
     if (!E9(9)){
      return false;
     }
     width = EA(E1[4], E1[5]);
     height = EA(E1[6], E1[7]);
     int i = E1[8];
     EE = EB(i, 128);
     ED = 2 << (i & 7);
     EF = EB(i, 64);
     F0 = null;
     return !EE || E6(ED, false);
    }
    private boolean E6(int i, boolean flag){
     int ai[] = new int[i];
     for (int j = 0; j < i; j++){
      if (!E9(3)){
       return false;
      }
      ai[j] = E1[0] << 16 | E1[1] << 8 | E1[2] | 0xff000000;
     }
     if (flag){
      E8 = ai;
     }else{
      F0 = ai;
     }
     return true;
    }
    private boolean E7(){
     if (!E9(1)){
      return false;
     }
     int i = E1[0];
     int j = -1;
     switch (i){
      case 249:
       j = E8();
       if (j < 0){
        return true;
       }
       if ((E1[0] & 1) != 0){
        E2 = E1[3];
       }else{
        E2 = -1;
       }
      break;
     }
     do{
      j = E8();
     }
     while (j > 0);
     return true;
    }
    private int E8(){
     if (!E9(1)){
      return -1;
     }
     int i = E1[0];
     if (i != 0 && !E9(i)){
      return -1;
     }else{
      return i;
     }
    }
    private boolean E9(int i){
     if (FA + i >= poolsize){
      return false;
     }
     for (int j = 0; j < i; j++){
      int k = C2[FA + j];
      if (k < 0){
       k += 256;
      }
      E1[j] = k;
     }
     FA += i;
     return true;
    }
    private static final int EA(int i, int j){
     return j << 8 | i;
    }
    private static final boolean EB(int i, int j){
     return (i & j) == j;
    }
   }

    public class GifFrame{ 
     /* 保存gif中所有帧的向量 */
     private Vector frames;  
     /* 当前播放的帧的索引 */
     private int index;
     public GifFrame(){
      frames = new Vector(1);
      index = 0;
     } 
     /* 添加一帧 */
     public void addImage(Bitmap image) {
      frames.addElement(image);
     }
     /* 返回帧数 */
     public int size() {
      return frames.size();
     }
     /* 得到当前帧的图片 */
     public Bitmap getImage() {
      if (size() == 0) {
       return null;
      } else{
       return (Bitmap) frames.elementAt(index);
      }
     }
     /* 下一帧 */
     public void nextFrame(){
      if (index + 1 < size()){
       index++;
      }else{
       index = 0;
      }
     }
     /* 创建GifFrame */
     public static GifFrame CreateGifImage(byte abyte0[]){
      try{
       GifFrame GF = new GifFrame();
       Bitmap image = null;
       GifDecoder gifdecoder = new GifDecoder(abyte0);
       for (; gifdecoder.moreFrames(); gifdecoder.nextFrame()){
        try{
          image = gifdecoder.decodeImage();
          if (GF != null && image != null){
           GF.addImage(image);
          }
          continue;
         }catch(Exception e){
          e.printStackTrace();
         }
         break;
        }
       gifdecoder.clear();
       gifdecoder = null;
       return GF;
      }catch (Exception e){
       e.printStackTrace();
       return null;
      }
     }
    }

    public class GameView extends View implements Runnable{
     Context  mContext = null;
     /* 声明GifFrame对象 */
     GifFrame mGifFrame = null;
     public GameView(Context context){
      super(context);
      mContext = context;
      /* 解析GIF动画 */
      mGifFrame=GifFrame.CreateGifImage(fileConnect(this.getResources().openRawResource(R.drawable.gif1)));
      /* 开启线程 */
      new Thread(this).start();
     }
     public void onDraw(Canvas canvas){
      super.onDraw(canvas);
      /* 下一帧 */
      mGifFrame.nextFrame();
      /* 得到当前帧的图片 */
      Bitmap b=mGifFrame.getImage(); 
      /* 绘制当前帧的图片 */
      if(b!=null)
       canvas.drawBitmap(b,10,10,null);
     }
     /**
      * 线程处理
     */
     public void run(){
      while (!Thread.currentThread().isInterrupted()){
       try{
        Thread.sleep(100);
       }catch (InterruptedException e){
        Thread.currentThread().interrupt();
       }
       //使用postInvalidate可以直接在线程中更新界面
        postInvalidate();
      }
     } 
     /* 读取文件 */
     public byte[] fileConnect(InputStream is){
      try{        
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       int ch = 0;
       while( (ch = is.read()) != -1) {
        baos.write(ch);
       }        
       byte[] datas = baos.toByteArray();
       baos.close();
       baos = null;
       is.close();
       is = null;
       return datas;
      }catch(Exception e){
       return null;
      }
     }
    }

    public class Activity01 extends Activity{
     private GameView mGameView = null;
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState){
      super.onCreate(savedInstanceState);
      mGameView = new GameView(this);
      setContentView(mGameView);
     }
    }

原文地址:http://blog.csdn.net/liubin8095/article/details/6974190

你可能感兴趣的:(Android手机游戏开发知识点总结)