游戏开发中的触摸事件
在游戏开发中监听屏幕触摸事件须要在View中重写父类onTouchEvent方法,在重写的方法中拦截用户触摸屏幕的一些信息,比如触摸屏幕的X 、 Y坐标 触摸屏幕发生的事件 触摸按下 触摸抬起 触摸移动,触摸屏幕发生的时间 等等, 我们先看看onTouchEvent的函数原型。函数中的Event 参数的意思为当前触摸事件的对象,这个对象中包含着当前触摸事件的一切信息。比如ecent.getAction()可以拿到当前触摸事件的名称,根据触摸事件的名称可以判断当前是触摸按下 还是 触摸移动 还是 触摸抬起。 event.getX()与 event.getY()可以拿到当前触摸屏幕的X Y坐标。event.getEventTime(); 可以拿到当前触发触摸事件的时间,等等所有的信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); mPosX = (int) event.getX(); mPosY = (int) event.getY(); switch (action) { // 触摸按下的事件 case MotionEvent.ACTION_DOWN: Log.v("test", "ACTION_DOWN"); break; // 触摸移动的事件 case MotionEvent.ACTION_MOVE: Log.v("test", "ACTION_MOVE"); break; // 触摸抬起的事件 case MotionEvent.ACTION_UP: Log.v("test", "ACTION_UP"); break; } // return super.onTouchEvent(event); return true; } |
这个函数是具有有返回值的,须要返回一个布尔值。大家发现我将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刷新屏幕重新显示图片 文字的位置以及内容。 具体相关内容见之前的文章。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; public class ViewActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MyView(this)); } public class MyView extends View { /** 触摸后绘制的图片 **/ Bitmap mBitmap = null; /** 游戏画笔 **/ Paint mPaint = null; /** 触摸后在屏幕中显示的位置 **/ int mPosX = 0; int mPosY = 0; /**事件触发时间**/ Long mActionTime = 0L; public MyView(Context context) { super(context); /** 设置当前View拥有控制焦点 **/ this.setFocusable(true); /** 设置当前View拥有触摸事件 **/ this.setFocusableInTouchMode(true); /** 加载图片 **/ mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.item); mPaint = new Paint(); mPaint.setColor(Color.WHITE); } @Override protected void onDraw(Canvas canvas) { /** 绘制图片 **/ canvas.drawBitmap(mBitmap, mPosX, mPosY, mPaint); canvas.drawText("当前X坐标:"+mPosX, 0, 20, mPaint); canvas.drawText("当前Y坐标:"+mPosY, 0, 40, mPaint); canvas.drawText("事件触发时间:"+mActionTime, 0, 60, mPaint); super.onDraw(canvas); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); mPosX = (int) event.getX(); mPosY = (int) event.getY(); switch (action) { // 触摸按下的事件 case MotionEvent.ACTION_DOWN: Log.v("test", "ACTION_DOWN"); break; // 触摸移动的事件 case MotionEvent.ACTION_MOVE: Log.v("test", "ACTION_MOVE"); break; // 触摸抬起的事件 case MotionEvent.ACTION_UP: Log.v("test", "ACTION_UP"); break; } /**得到事件触发时间**/ mActionTime = event.getEventTime(); /** 通知UI线程刷新屏幕 **/ postInvalidate(); // return super.onTouchEvent(event); return true; } } } |
2.多点触摸
由于模拟器只能用鼠标点击一个点 无法模拟多点触摸,所以我用真机来调试多点触摸。下面这张图是我用豌豆荚在真机中截的图,此时我两只手指正在手机屏幕中触摸移动。界面中正确的根据我的手势来移动图片以及显示的内容。这里强调一下多点触摸并不是所有手机都支持 有些手机支持很多点有些手机可能只支持单点。就那我的手机来说只支持两点触摸。所以无论我用多少根手指头在我的手机屏幕上比划 也只会出现2个触摸点,如下图所示。
下面我们详细的说一下代码的实现方式,多点触摸和单点触摸一样都是在onTouchEvent中去监听触摸事件。调用方法event.getPointerCount(); 可以拿到当前屏幕同时触摸点的数量 以我的手机为例因为只支持两点触摸所以在我的手机上调用该方法最多只会返回2。 拿到了触摸屏幕点的数量以后 可以使用for循环来遍历当前屏幕的所有触摸点,调用event.getX(i); 与 event.getY(i); 方法 将ID作为参数传入会得到每个点在屏幕中显示的X Y坐标值。最后根据坐标值将图片与内容绘制在手机屏幕中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.Window; import android.view.WindowManager; import android.view.SurfaceHolder.Callback; public class SurfaceViewAcitvity extends Activity { MyView mAnimView = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 全屏显示窗口 requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 显示自定义的游戏View mAnimView = new MyView(this); setContentView(mAnimView); } public class MyView extends SurfaceView implements Callback { /** 触摸后绘制的图片 **/ Bitmap mBitmap = null; /** 游戏画笔 **/ Paint mPaint = null; SurfaceHolder mSurfaceHolder = null; /** 控制游戏更新循环 **/ boolean mRunning = false; /** 游戏画布 **/ Canvas mCanvas = null; public MyView(Context context) { super(context); /** 设置当前View拥有控制焦点 **/ this.setFocusable(true); /** 设置当前View拥有触摸事件 **/ this.setFocusableInTouchMode(true); /** 加载图片 **/ mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.item); /** 拿到SurfaceHolder对象 **/ mSurfaceHolder = this.getHolder(); /** 将mSurfaceHolder添加到Callback回调函数中 **/ mSurfaceHolder.addCallback(this); /** 创建画布 **/ mCanvas = new Canvas(); /**创建画笔**/ mPaint = new Paint(); mPaint.setColor(Color.WHITE); } @Override public boolean onTouchEvent(MotionEvent event) { /** 拿到触摸的状态 **/ int action = event.getAction(); /** 控制当触摸抬起时清屏 **/ boolean reset = false; switch (action) { // 触摸按下的事件 case MotionEvent.ACTION_DOWN: Log.v("test", "ACTION_DOWN"); break; // 触摸移动的事件 case MotionEvent.ACTION_MOVE: Log.v("test", "ACTION_MOVE"); break; // 触摸抬起的事件 case MotionEvent.ACTION_UP: Log.v("test", "ACTION_UP"); reset = true; break; } // 在这里加上线程安全锁 synchronized (mSurfaceHolder) { /** 拿到当前画布 然后锁定 **/ mCanvas = mSurfaceHolder.lockCanvas(); /** 清屏 **/ mCanvas.drawColor(Color.BLACK); if (!reset) { /** 在屏幕中拿到同时触碰的点的数量 **/ int pointCount = event.getPointerCount(); /** 使用循环将每个触摸点图片都绘制出来 **/ for (int i = 0; i < pointCount; i++) { /** 根据触摸点的ID 可以讲每个触摸点的X Y坐标拿出来 **/ int x = (int) event.getX(i); int y = (int) event.getY(i); int showX = i * 150; mCanvas.drawBitmap(mBitmap, x, y, mPaint); mCanvas.drawText("当前X坐标:"+x, showX, 20, mPaint); mCanvas.drawText("当前Y坐标:"+y, showX, 40, mPaint); mCanvas.drawText("事件触发时间:"+event.getEventTime(), showX, 60, mPaint); } }else { mCanvas.drawText("请多点触摸当前手机屏幕" ,0, 20, mPaint); } /** 绘制结束后解锁显示在屏幕上 **/ mSurfaceHolder.unlockCanvasAndPost(mCanvas); } // return super.onTouchEvent(event); return true; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } } } |
总体来说这章内容还是比较简单的,老规矩每篇文章都会附带源代码,最后如果你还是觉得我写的不够详细 看的不够爽 不要紧我把源代码的下载地址贴出来 欢迎大家一起讨论学习雨松MOMO希望可以和大家一起进步。
- 本文固定链接: https://www.xuanyusong.com/archives/324
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!
怎么实现左半边右半边屏幕点击时候的效应不同,比如点左边小球顺时针转,点右边小球逆时针转
触摸屏来控制人物动作怎么实现?
问题大概解决了,参考了http://blog.csdn.net/xiaominghimi/article/details/6180606
为什么实际测试发现坐标不对呢?我的手机485×800,但发现在应用中取得的屏幕大小是320×569,这也导致触点坐标不对了,为什么呢?我在himi的关于box2d的例子也发现存在这个问题,但有些就没有,好奇怪啊?fyjc–999@163.com