
游戏开发中的触摸事件
在游戏开发中监听屏幕触摸事件须要在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刷新屏幕重新显示图片 文字的位置以及内容。 具体相关内容见Android游戏开发之构建游戏框架View与SurFaceView的区别(五)

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);
this.setFocusable(true);
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();
postInvalidate();
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);
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);
this.setFocusable(true);
this.setFocusableInTouchMode(true);
mBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.item);
mSurfaceHolder = this.getHolder();
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++) {
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 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) {
}
}
} |