android游戏开发(二)触屏事件处理

本文详细介绍了Android中触摸屏事件的处理方式,包括如何去除标题栏和状态栏、如何实现图片随触摸移动等功能。同时,还讲解了Android坐标系的概念及如何通过重写onTouchEvent方法实现人机交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原创作品,允许转载,转载时请务必以超链接形式标明文章  原始出处 、作者信息和本声明。否则将追究法律责任。 http://mahaile.blog.51cto.com/2891586/831048

 在上一章我 我们没有把标题栏和状态栏给去掉  ,  如果在游戏中 是不会显示 显示标题栏和状态栏的, 如何去掉了, 很简单,  在mainActivity 的onCreate方法中加入下面两句 即可  :

 

 requestWindowFeature(Window.FEATURE_NO_TITLE); //设置无标题

 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //设置全屏

 赶紧去试试吧 , 写程序就是要 多试 嘻嘻..


图片有了 ,我们怎么样才能让图片有行为呢 ?  那就需要人机交互了,通过触摸屏让游戏具有行为

先在这里 说明下android 的坐标系

android 的坐标系  左上定点为原点坐标(0,0), 向右为X轴,向下为Y轴 说明这个位置是因为有些游戏引擎是 以 左下为原点的哦 , 大家要记住喔,后面如果用引擎的话 也有个概念

下面 我们来看看android 的 触摸屏事件是怎么处理的

我们先来分析下 现在的用户界面 都是通过事件驱动 实现人机交互的,当屏幕的界面接受到事件时 根据不同情况 进行不同的处理 就可以实现人机交互了

android 支持的触摸屏事件有:按下、弹起、移动、双击、长按、滑动。

按下、弹起、移动(down、move、up)是简单的触摸屏事件 我们本章就来说说这个东东.

而双击、长按、滑动、滚动需要根据运动的轨迹来做识别的。在Android中有专门的类去识别,android.view.GestureDetector。 这一块我们后面的章节 在讲


那如何实现呢?

 在Android中任何一个控件和Activity都是间接或者直接继承于android.view.View。一个View对象可以处理测距、布局、绘制、焦点变换、滚动条,以及触屏区域自己表现的按键和手势,因为我们的view 是继承了surfaceView,surfaceView又是继承view 所以要实现简单的触摸屏事件,只需要重写父类view 里面的onTouchEvent 方法就可以实现简单的触屏屏事件了 


下面我们来实现一个功能  用上一章的程序 来实现 把图片显示在点击触摸屏的地方和图片能根据手指移动而移动


直接看代码 

package yxqz.com;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;

/**
 * android surfaceview触摸屏事件学习
 * @author mahaile
 *
 */
public class GameSurfaceView extends SurfaceView implements Callback{
	boolean flag; //线程标示位 当为false时停止刷新界面
	SurfaceHolder surfaceHolder;
	GameViewThread gameViewThread;
	float x=0,y=0;
	int direction=0;  //图片运行方向 控制图片向上 或向下运动
	int width,height;
	Bitmap bitmap_role;
	public GameSurfaceView(Context context) {
		super(context);
		surfaceHolder=this.getHolder();
		surfaceHolder.addCallback(this); //添加回调
		bitmap_role=BitmapFactory.decodeResource(getResources(), R.drawable.role);
		
		//设置焦点 如果不设置焦点的话 在该界面下 点击触摸屏是无效的 默认为false
		 setFocusable(true);
	}
	
	public void onDraw(Canvas canvas){
		canvas.drawColor(Color.BLACK);
		canvas.drawBitmap(bitmap_role, x-bitmap_role.getWidth()/2, y-bitmap_role.getHeight()/2, null);
	}
    //重写父类中的 onTouchEvent就可以监听到  触摸事件了 记住要设置焦点喔 
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if(event.getAction()==MotionEvent.ACTION_DOWN){ //处理屏幕屏点下事件 手指点击屏幕时触发
			x=event.getX();
			y=event.getY();
		}else if(event.getAction()==MotionEvent.ACTION_UP){//处理屏幕屏抬起事件  手指离开屏幕时触发
			
		}else if(event.getAction()==MotionEvent.ACTION_MOVE){//处理移动事件 手指在屏幕上移动时触发
			x=event.getX();
			y=event.getY();
		}
		return true;  //此处需要返回true 才可以正常处理move事件 详情见后面的  说明
	}
	
	public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {	
	}

	public void surfaceCreated(SurfaceHolder surfaceHolder) {
		//获取屏幕的 宽高 只有在 surface创建的时候 才有效 ,才构造方法中获取 宽高是获取不到的
		width=this.getWidth();
		height=this.getHeight();
		//初始化绘图线程
		gameViewThread=new GameViewThread();
		gameViewThread.flag=true;
		gameViewThread.start();
	}
	public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
		gameViewThread.flag=false; //销毁线程
	}

	class GameViewThread extends Thread{
		public boolean flag;
		public void run(){
			while(flag){
				Canvas canvas=null;
				try{
					canvas=surfaceHolder.lockCanvas(); //锁定画布 并获取canvas
					onDraw(canvas);//调用onDraw 渲染到屏幕
					surfaceHolder.unlockCanvasAndPost(canvas); //此步不要忘记了喔 否则界面上显示不出来的
				}catch(Exception e){
					e.printStackTrace();
				}
				try {
					Thread.sleep(10);//线程休眠时间  控制帧数
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
			}  //每10毫秒刷新一次
			}
		}
	}
}

MainActivity 类  这里就不贴代码了,因为和上一章一样 ,很简单的

onTouchEvent() 返回值 解释

解释:

    onTouchEvent(),预设使用Oeverride这个方法,通常情況下去呼叫super.onTouchEvent()并传回布林值。但是这里要注意一点,预设如果去呼叫super.onTouchEvent()則很有可能super里面并没做任何事,并且回传false回來,一旦回传false回來,很可能后面的event (例如:Action_Move、Action_Up) 都会收不到了,所以为了确保保后面event能順利收到,要注意是否要直接呼super.TouchEvent()。


 

下一张 我们看看如果使用android的手势识别


 

最后还要注意一点:在初始化的时候不要忘记setFocusableInTouchMode(true);触屏模式获取焦点,比较类似 setFocusable(true);

        ——setFocusable(true);//此方法是用来响应按键!如果是自己定义一个继承自View的类,重新实现onKeyDown方法后,只有当该View获得焦点时才会调用onKeyDown方法,Actvity中的onKeyDown方法是当所有控件均没有处理该按键事件时,才会调用.


原代码下载地址

http://download.csdn.net/detail/ma_haile/4215113


补充点 :

  在android 中使用触摸屏 在模拟机中 我们的鼠标当点击一次模拟器屏幕然后释放,先触发 ACTION_DOWN 然后 ACTION_UP ;如果是在屏幕上移动那么才会触发 ACTION_MOVE 的动作;这个很正常, 但在真机中呢 ,是不是 也是这样的呢 ?  答案是否定的  如果我们那真机测试的话 流程如下

先触发 ACTION_DOWN 如果手指不抬起的话 会一直触发ACTION_MOVE事件(就是不移动也会触发)  然后 ACTION_UP

原因有两点:第一点是因为,Android 对于触屏事件很敏感!第二点:虽然我们的手指感觉是静止没有移动,其实事实不是如此!当我们的手指触摸到手机屏幕上之后,感觉静止没动,其实手指在不停的微颤抖震动。 所以才会一直触发action_move事件   

这样的情况对我们的程序有什么影响呢 

 

比如我们app线程绘图时间每次用了10ms,当手指触摸屏幕,这短暂的0.1秒内大概会产生10个左右的MotionEvent ,并且系统会尽可能快的把这些event发给监听线程, 这样的话在这一段时间内cpu可能忙于处理onTouchEvent事件 从而造成app 的界面没有足够资源去处理,而照成界面刷新一卡一卡的。

那么我们其实根本用不着按键响应这么多次,而是需要在我们每次绘图后,或者绘图前接受一次用户触摸事件就OK了,这样能让帧率不至于下降的太厉害不是么?!如果我们能把触屏监听事件 触发的事件 给慢下来 不就是可以解决这个问题了吗  ,嘻嘻 就是这么优化的

@Override
public boolean onTouchEvent(MotionEvent event) {
	if(event.getAction()==MotionEvent.ACTION_DOWN){ 
	}else if(event.getAction()==MotionEvent.ACTION_UP){
	}else if(event.getAction()==MotionEvent.ACTION_MOVE){
	}
         synchronized(this){
           try{
               this.wait(Time);     //让事件线程休眠 减少触发次数
            }catch(InterruptedException e){
             e.printStackTrace();
           }         
          }
	return true;
 }

 上面的代码 加到你的onTouch 里面 但有一点要注意喔 ,上面的线程同步对象使用了this ,如果这个类 也被别的类作为同步对象的话 ,可能发生死锁喔,  如果这个类已经被作为了同步对象的话 ,  我们重新初始化的时候 新new 一个对象 作为onTouch的同步对象就可以了

本文出自 “android,unity3d” 博客,请务必保留此出处http://mahaile.blog.51cto.com/2891586/831048

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值