游戏开发中的触摸事件
在游戏开发中监听屏幕触摸事件须要在View中重写父类onTouchEvent方法,在重写的方法中拦截用户触摸屏幕的一些信息,比如触摸屏幕的X 、 Y坐标 触摸屏幕发生的事件 触摸按下 触摸抬起 触摸移动,触摸屏幕发生的时间 等等, 我们先看看onTouchEvent的函数原型。函数中的Event 参数的意思为当前触摸事件的对象,这个对象中包含着当前触摸事件的一切信息。比如ecent.getAction()可以拿到当前触摸事件的名称,根据触摸事件的名称可以判断当前是触摸按下 还是 触摸移动 还是 触摸抬起。 event.getX()与 event.getY()可以拿到当前触摸屏幕的X Y坐标。event.getEventTime(); 可以拿到当前触发触摸事件的时间,等等所有的信息。
- @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刷新屏幕重新显示图片 文字的位置以及内容。 具体相关内容见之前的文章。
- 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坐标值。最后根据坐标值将图片与内容绘制在手机屏幕中。
- 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) {
- }
- }
- }
总体来说这章内容还是比较简单的,老规矩每篇文章都会附带源代码,最后如果你还是觉得我写的不够详细,看的不够爽,不要紧我把源代码的下载地址贴出来,欢迎大家一起讨论学习,希望可以和大家一起进步。
下载地址:http://vdisk.weibo.com/s/aaioV
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。