Android游戏开发之单点触摸与多点触摸的响应方式(二十三)

100
回复
888135
查看
  [复制链接]

249

主题

278

帖子

17

安币

初级码农

Rank: 1

发表于 2011-9-3 00:52:31 | 显示全部楼层 |阅读模式
Android游戏开发之单点触摸与多点触摸的响应方式
游戏开发中的触摸事件


         在游戏开发中监听屏幕触摸事件须要在View中重写父类onTouchEvent方法,在重写的方法中拦截用户触摸屏幕的一些信息,比如触摸屏幕的X 、 Y坐标 触摸屏幕发生的事件 触摸按下  触摸抬起  触摸移动,触摸屏幕发生的时间 等等, 我们先看看onTouchEvent的函数原型。
   
    函数中的Event 参数的意思为当前触摸事件的对象,这个对象中包含着当前触摸事件的一切信息。比如ecent.getAction()可以拿到当前触摸事件的名称,根据触摸事件的名称可以判断当前是触摸按下 还是 触摸移动 还是 触摸抬起。 event.getX()与 event.getY()可以拿到当前触摸屏幕的X Y坐标。event.getEventTime(); 可以拿到当前触发触摸事件的时间,等等所有的信息。
  1.         @Override
  2.         public boolean onTouchEvent(MotionEvent event) {
  3.             int action = event.getAction();
  4.             mPosX = (int) event.getX();
  5.             mPosY = (int) event.getY();
  6.             switch (action) {
  7.             // 触摸按下的事件
  8.             case MotionEvent.ACTION_DOWN:
  9.                 Log.v("test", "ACTION_DOWN");
  10.                 break;
  11.             // 触摸移动的事件
  12.             case MotionEvent.ACTION_MOVE:
  13.                 Log.v("test", "ACTION_MOVE");
  14.                 break;
  15.             // 触摸抬起的事件
  16.             case MotionEvent.ACTION_UP:
  17.                 Log.v("test", "ACTION_UP");
  18.                 break;
  19.             }
  20. //            return super.onTouchEvent(event);
  21.             return true;
  22.         }
复制代码
这个函数是具有有返回值的,须要返回一个布尔值。大家发现我将return super.onTouchEvent(event)注释掉了而是直接return ture。 我给同学们解释一下为什么要着么操作。onTouchEvent方法不是我们手动调用的而是系统调用的 它的返回值会直接通知系统是否回调方法。如果说在这里return false  onTouchEvent方法永远不会在被回调也就是说它只能响应触摸按下操作,触摸移动事件 和触摸抬起事件永远都不会在被响应 ,log只会打印出"ACTION_DOWN"。 如果这里return super.onTouchEvent(event); 调用父类的方法来得到返回值返回 ,这样也是有问题的因为调用父类的onTouchEvent方法可能也会返回false 这样一来依然会无法响应触摸移动事件和触摸抬起事件。所以为了正确的处理触摸事件在这里我们直接return ture 这样一来就万无一失了,Log中会将所有信息都打印出来。



1.单点触摸

        在下面这个DEMO中 用手触摸 移动 屏幕后 下面的icon图片会跟随这我的手势移动。 代码实现主要是在onTouchEvent方法中时时去计算手触摸屏幕各个状态的坐标 然后调用 postInvalidate(); 方法去通知UI刷新屏幕重新显示图片 文字的位置以及内容。 具体相关内容见Android游戏开发之构建游戏框架View与SurFaceView的区别(五)
  1. import android.app.Activity;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.graphics.Canvas;
  6. import android.graphics.Color;
  7. import android.graphics.Paint;
  8. import android.os.Bundle;
  9. import android.util.Log;
  10. import android.view.MotionEvent;
  11. import android.view.View;

  12. public class ViewActivity extends Activity {
  13.     @Override
  14.     public void onCreate(Bundle savedInstanceState) {
  15.         super.onCreate(savedInstanceState);
  16.         setContentView(new MyView(this));
  17.     }

  18.     public class MyView extends View {

  19.         /** 触摸后绘制的图片 **/
  20.         Bitmap mBitmap = null;

  21.         /** 游戏画笔 **/
  22.         Paint mPaint = null;

  23.         /** 触摸后在屏幕中显示的位置 **/
  24.         int mPosX = 0;
  25.         int mPosY = 0;
  26.        
  27.         /**事件触发时间**/
  28.         Long mActionTime = 0L;
  29.        
  30.         public MyView(Context context) {
  31.             super(context);
  32.             /** 设置当前View拥有控制焦点 **/
  33.             this.setFocusable(true);
  34.             /** 设置当前View拥有触摸事件 **/
  35.             this.setFocusableInTouchMode(true);
  36.             /** 加载图片 **/
  37.             mBitmap = BitmapFactory.decodeResource(getResources(),
  38.                     R.drawable.item);
  39.             mPaint = new Paint();
  40.             mPaint.setColor(Color.WHITE);
  41.         }

  42.         @Override
  43.         protected void onDraw(Canvas canvas) {
  44.             /** 绘制图片 **/
  45.             canvas.drawBitmap(mBitmap, mPosX, mPosY, mPaint);
  46.             canvas.drawText("当前X坐标:"+mPosX, 0, 20, mPaint);
  47.             canvas.drawText("当前Y坐标:"+mPosY, 0, 40, mPaint);
  48.             canvas.drawText("事件触发时间:"+mActionTime, 0, 60, mPaint);
  49.             super.onDraw(canvas);
  50.         }

  51.         @Override
  52.         public boolean onTouchEvent(MotionEvent event) {

  53.             int action = event.getAction();
  54.             mPosX = (int) event.getX();
  55.             mPosY = (int) event.getY();
  56.             switch (action) {
  57.             // 触摸按下的事件
  58.             case MotionEvent.ACTION_DOWN:
  59.                 Log.v("test", "ACTION_DOWN");
  60.                 break;
  61.             // 触摸移动的事件
  62.             case MotionEvent.ACTION_MOVE:
  63.                 Log.v("test", "ACTION_MOVE");
  64.                 break;
  65.             // 触摸抬起的事件
  66.             case MotionEvent.ACTION_UP:
  67.                 Log.v("test", "ACTION_UP");
  68.                 break;
  69.             }
  70.             /**得到事件触发时间**/
  71.             mActionTime = event.getEventTime();
  72.             /** 通知UI线程刷新屏幕 **/
  73.             postInvalidate();
  74.             // return super.onTouchEvent(event);
  75.             return true;
  76.         }
  77.     }
  78. }
复制代码
2.多点触摸

         
         由于模拟器只能用鼠标点击一个点 无法模拟多点触摸,所以我用真机来调试多点触摸。下面这张图是我用豌豆荚在真机中截的图,此时我两只手指正在手机屏幕中触摸移动。界面中正确的根据我的手势来移动图片以及显示的内容。这里强调一下多点触摸并不是所有手机都支持 有些手机支持很多点有些手机可能只支持单点。就那我的手机来说只支持两点触摸。所以无论我用多少根手指头在我的手机屏幕上比划 也只会出现2个触摸点,如下图所示。



        下面我们详细的说一下代码的实现方式,多点触摸和单点触摸一样都是在onTouchEvent中去监听触摸事件。调用方法event.getPointerCount(); 可以拿到当前屏幕同时触摸点的数量 以我的手机为例因为只支持两点触摸所以在我的手机上调用该方法最多只会返回2。 拿到了触摸屏幕点的数量以后 可以使用for循环来遍历当前屏幕的所有触摸点,调用event.getX(i); 与 event.getY(i); 方法 将ID作为参数传入会得到每个点在屏幕中显示的X Y坐标值。最后根据坐标值将图片与内容绘制在手机屏幕中。
  1. import android.app.Activity;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.graphics.Canvas;
  6. import android.graphics.Color;
  7. import android.graphics.Paint;
  8. import android.os.Bundle;
  9. import android.util.Log;
  10. import android.view.MotionEvent;
  11. import android.view.SurfaceHolder;
  12. import android.view.SurfaceView;
  13. import android.view.Window;
  14. import android.view.WindowManager;
  15. import android.view.SurfaceHolder.Callback;


  16. public class SurfaceViewAcitvity extends Activity {

  17.     MyView mAnimView = null;

  18.     @Override
  19.     public void onCreate(Bundle savedInstanceState) {
  20.         super.onCreate(savedInstanceState);
  21.         // 全屏显示窗口
  22.         requestWindowFeature(Window.FEATURE_NO_TITLE);
  23.         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  24.                 WindowManager.LayoutParams.FLAG_FULLSCREEN);
  25.         // 显示自定义的游戏View
  26.         mAnimView = new MyView(this);
  27.         setContentView(mAnimView);
  28.     }

  29.     public class MyView extends SurfaceView implements Callback {

  30.         /** 触摸后绘制的图片 **/
  31.         Bitmap mBitmap = null;

  32.         /** 游戏画笔 **/
  33.         Paint mPaint = null;

  34.         SurfaceHolder mSurfaceHolder = null;

  35.         /** 控制游戏更新循环 **/
  36.         boolean mRunning = false;

  37.         /** 游戏画布 **/
  38.         Canvas mCanvas = null;

  39.         public MyView(Context context) {
  40.             super(context);
  41.             /** 设置当前View拥有控制焦点 **/
  42.             this.setFocusable(true);
  43.             /** 设置当前View拥有触摸事件 **/
  44.             this.setFocusableInTouchMode(true);
  45.             /** 加载图片 **/
  46.             mBitmap = BitmapFactory.decodeResource(getResources(),
  47.                     R.drawable.item);
  48.             /** 拿到SurfaceHolder对象 **/
  49.             mSurfaceHolder = this.getHolder();
  50.             /** 将mSurfaceHolder添加到Callback回调函数中 **/
  51.             mSurfaceHolder.addCallback(this);
  52.             /** 创建画布 **/
  53.             mCanvas = new Canvas();
  54.             /**创建画笔**/
  55.             mPaint = new Paint();
  56.             mPaint.setColor(Color.WHITE);
  57.         }

  58.         @Override
  59.         public boolean onTouchEvent(MotionEvent event) {
  60.             /** 拿到触摸的状态 **/
  61.             int action = event.getAction();
  62.             /** 控制当触摸抬起时清屏 **/
  63.             boolean reset = false;
  64.             switch (action) {
  65.             // 触摸按下的事件
  66.             case MotionEvent.ACTION_DOWN:
  67.                 Log.v("test", "ACTION_DOWN");
  68.                 break;
  69.             // 触摸移动的事件
  70.             case MotionEvent.ACTION_MOVE:
  71.                 Log.v("test", "ACTION_MOVE");
  72.                 break;
  73.             // 触摸抬起的事件
  74.             case MotionEvent.ACTION_UP:
  75.                 Log.v("test", "ACTION_UP");
  76.                 reset = true;
  77.                 break;
  78.             }

  79.             // 在这里加上线程安全锁
  80.             synchronized (mSurfaceHolder) {
  81.                 /** 拿到当前画布 然后锁定 **/
  82.                 mCanvas = mSurfaceHolder.lockCanvas();
  83.                 /** 清屏 **/
  84.                 mCanvas.drawColor(Color.BLACK);

  85.                 if (!reset) {
  86.                     /** 在屏幕中拿到同时触碰的点的数量 **/
  87.                     int pointCount = event.getPointerCount();

  88.                     
  89.                     /** 使用循环将每个触摸点图片都绘制出来 **/
  90.                     for (int i = 0; i < pointCount; i++) {
  91.                         /** 根据触摸点的ID 可以讲每个触摸点的X Y坐标拿出来 **/
  92.                         int x = (int) event.getX(i);
  93.                         int y = (int) event.getY(i);
  94.                         int showX = i * 150;
  95.                         mCanvas.drawBitmap(mBitmap, x, y, mPaint);
  96.                         mCanvas.drawText("当前X坐标:"+x, showX, 20, mPaint);
  97.                         mCanvas.drawText("当前Y坐标:"+y, showX, 40, mPaint);
  98.                         mCanvas.drawText("事件触发时间:"+event.getEventTime(), showX, 60, mPaint);
  99.                     }
  100.                 }else {
  101.                     mCanvas.drawText("请多点触摸当前手机屏幕" ,0, 20, mPaint);
  102.                 }
  103.                 /** 绘制结束后解锁显示在屏幕上 **/
  104.                 mSurfaceHolder.unlockCanvasAndPost(mCanvas);
  105.             }

  106.             // return super.onTouchEvent(event);
  107.             return true;
  108.         }
  109.        
  110.         @Override
  111.         public void surfaceChanged(SurfaceHolder holder, int format, int width,
  112.                 int height) {

  113.         }

  114.         @Override
  115.         public void surfaceCreated(SurfaceHolder holder) {

  116.         }

  117.         @Override
  118.         public void surfaceDestroyed(SurfaceHolder holder) {

  119.         }
  120.     }
  121. }
复制代码
总体来说这章内容还是比较简单的,老规矩每篇文章都会附带源代码,最后如果你还是觉得我写的不够详细 看的不够爽 不要紧我把源代码的下载地址贴出来 欢迎大家一起讨论学习

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

0

主题

380

帖子

715

安币

代码手工艺人

Rank: 4

发表于 2011-9-3 20:13:14 | 显示全部楼层
学习了~!

14

主题

361

帖子

204

安币

攻城狮

Rank: 3Rank: 3

发表于 2011-9-7 14:32:06 | 显示全部楼层
Android游戏开发之单点触摸与多点触摸的响应方式(二十三)

1

主题

25

帖子

12

安币

初级码农

Rank: 1

发表于 2011-9-13 13:37:49 | 显示全部楼层
好东西。学习了。

0

主题

49

帖子

19

安币

程序猿

Rank: 2

QQ达人

发表于 2011-9-13 16:51:28 | 显示全部楼层
学习了~!

0

主题

21

帖子

0

安币

初级码农

Rank: 1

发表于 2011-9-14 13:49:26 | 显示全部楼层
谢谢楼主分享

0

主题

21

帖子

13

安币

初级码农

Rank: 1

QQ达人

发表于 2011-9-15 12:54:19 | 显示全部楼层
感谢楼主发布,谢谢。

0

主题

12

帖子

22

安币

初级码农

Rank: 1

发表于 2011-10-27 08:57:21 | 显示全部楼层
谢谢楼主!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粤ICP备15117877号 )