`

《Beginning Android Games》给出基本框架的实现(2)

 
阅读更多

这里是关于Input部分的实现,处理所有操作输入,下面是AndroidInput的具体代码

 

public class AndroidInput implements Input {
	AccelerometerHandler accelHandler;
	KeyboardHandler keyHandler;
	TouchHandler touchHandler;
	
	public AndroidInput(Context context, View view, float scaleX, float scaleY){
		accelHandler=new AccelerometerHandler(context);
		keyHandler=new KeyboardHandler(view);
		if(Integer.parseInt(VERSION.SDK)<5){
			touchHandler=new SingleTouchHandler(view, scaleX, scaleY);
		}else{
			touchHandler=new MultiTouchHandler(view, scaleX, scaleY);
		}
	}
	
	@Override
	public float getAccelX() {
		return accelHandler.getAccelX();
	}

	@Override
	public float getAccelY() {
		return accelHandler.getAccelY();
	}

	@Override
	public float getAccelZ() {
		return accelHandler.getAccelZ();
	}

	@Override
	public List<KeyEvent> getKeyEvents() {
		return keyHandler.getKeyEvents();
	}

	@Override
	public List<TouchEvent> getTouchEvents() {
		return touchHandler.getTouchEvents();
	}

	@Override
	public int getTouchX(int pointer) {
		return touchHandler.getTouchX(pointer);
	}

	@Override
	public int getTouchY(int pointer) {
		return touchHandler.getTouchY(pointer);
	}

	@Override
	public boolean isKeyPressed(int keyCode) {
		return keyHandler.isKeyPressed(keyCode);
	}

	@Override
	public boolean isTouchDown(int pointer) {
		return touchHandler.isTouchDown(pointer);
	}

}

 

 

可以看到Input的输入其实分为三类,分别是传感器,键盘以及触屏,分别对应的3个Handler,而在触屏的出来上还有比较特殊的一点,因为多点触控是从API5才开始的,所以需要判断之后,决定使用单点还是多点触控

先从比较清晰简单的开始,传感器AccelerometerHandler

 

public class AccelerometerHandler implements SensorEventListener {
	float accelX;
	float accelY;
	float accelZ;
	
	public AccelerometerHandler(Context context){
		SensorManager manager=(SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
		if(manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size()!=0){
			Sensor accelermeter=manager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0);
			manager.registerListener(this, accelermeter, SensorManager.SENSOR_DELAY_GAME);
		}
	}
	
	@Override
	public void onAccuracyChanged(Sensor sensor, int accuray) {
		
	}

	@Override
	public void onSensorChanged(SensorEvent event) {
		accelX=event.values[0];
		accelY=event.values[1];
		accelZ=event.values[2];
	}

	public float getAccelX() {
		return accelX;
	}

	public float getAccelY() {
		return accelY;
	}

	public float getAccelZ() {
		return accelZ;
	}
	
	
}

 

 然后来看单点和多点触控的部分SingleTouchHandler和MultiTouchHandler,以及父类TouchHandler

public interface TouchHandler extends OnTouchListener {
	public boolean isTouchDown(int pointer);
	public int getTouchX(int pointer);
	public int getTouchY(int pointer);
	public List<TouchEvent> getTouchEvents();
} 

 

public class SingleTouchHandler implements TouchHandler {
	boolean isTouched;
	int touchX;
	int touchY;
	Pool<TouchEvent> touchEventPool;
	List<TouchEvent> touchEvents=new ArrayList<TouchEvent>();
	List<TouchEvent> touchEventsBuffer=new ArrayList<TouchEvent>();
	float scaleX;
	float scaleY;
	
	public SingleTouchHandler(View view, float scaleX, float scaleY){
		PoolObjectFactory<TouchEvent> factory=new PoolObjectFactory<TouchEvent>(){
			@Override
			public TouchEvent createObject() {
				return new TouchEvent();
			}
		};
		touchEventPool=new Pool<TouchEvent>(factory,100);
		view.setOnTouchListener(this);
		
		this.scaleX=scaleX;
		this.scaleY=scaleY;
	}
	
	@Override
	public List<TouchEvent> getTouchEvents() {
		synchronized (this) {
			int len=touchEvents.size();
			for(int i=0;i<len;i++){
				touchEventPool.free(touchEvents.get(i));
			}
			touchEvents.clear();
			touchEvents.addAll(touchEventsBuffer);
			touchEventsBuffer.clear();
			return touchEvents;
		}
	}

	@Override
	public int getTouchX(int pointer) {
		synchronized (this) {
			return touchX;
		}
	}

	@Override
	public int getTouchY(int pointer) {
		synchronized (this) {
			return touchY;
		}
	}

	@Override
	public boolean isTouchDown(int pointer) {
		synchronized (this) {
			if(pointer==0){
				return isTouched;
			}else{
				return false;
			}
		}
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		synchronized (this) {
			TouchEvent touchEvent=touchEventPool.newObject();
			switch(event.getAction()){
			case MotionEvent.ACTION_DOWN:
				touchEvent.type=TouchEvent.TOUCH_DOWN;
				isTouched=true;
				break;
			case MotionEvent.ACTION_MOVE:
				touchEvent.type=TouchEvent.TOUCH_DRAGGED;
				isTouched=true;
				break;
			case MotionEvent.ACTION_CANCEL:
			case MotionEvent.ACTION_UP:
				touchEvent.type=TouchEvent.TOUCH_UP;
				isTouched=false;
				break;
			}
			
			touchEvent.x=touchX=(int)(event.getX()*scaleX);
			touchEvent.y=touchY=(int)(event.getY()*scaleY);
			touchEventsBuffer.add(touchEvent);
			
			return true;
		}
	}

}

 

 

public class MultiTouchHandler implements TouchHandler {
	boolean[] isTouched=new boolean[20];
	int[] touchX=new int[20];
	int[] touchY=new int[20];
	Pool<TouchEvent> touchEventPool;
	List<TouchEvent> touchEvents=new ArrayList<TouchEvent>();
	List<TouchEvent> touchEventsBuffer=new ArrayList<TouchEvent>();
	float scaleX;
	float scaleY;
	
	public MultiTouchHandler(View view, float scaleX, float scaleY){
		PoolObjectFactory<TouchEvent> factory=new PoolObjectFactory<TouchEvent>(){
			@Override
			public TouchEvent createObject() {
				return new TouchEvent();
			}};
		touchEventPool=new Pool<TouchEvent>(factory,100);
		view.setOnTouchListener(this);
		
		this.scaleX=scaleX;
		this.scaleY=scaleY;
	}
	@Override
	public List<TouchEvent> getTouchEvents() {
		synchronized (this) {
			int len=touchEvents.size();
			for(int i=0;i<len;i++){
				touchEventPool.free(touchEvents.get(i));
			}
			touchEvents.clear();
			touchEvents.addAll(touchEventsBuffer);
			touchEventsBuffer.clear();
			return touchEvents;
		}
	}

	@Override
	public int getTouchX(int pointer) {
		synchronized (this) {
			if(pointer<0||pointer>=20){
				return 0;
			}else{
				return touchX[pointer];
			}
		}
	}

	@Override
	public int getTouchY(int pointer) {
		synchronized (this) {
			if(pointer<0||pointer>=20){
				return 0;
			}else{
				return touchY[pointer];
			}
		}
	}

	@Override
	public boolean isTouchDown(int pointer) {
		synchronized (this) {
			if(pointer<0||pointer>=20){
				return false;
			}else{
				return isTouched[pointer];
			}
		}
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		synchronized (this) {
			int action=event.getAction()&MotionEvent.ACTION_MASK;
			int pointerIndex=(event.getAction()&MotionEvent.ACTION_POINTER_ID_MASK)>>MotionEvent.ACTION_POINTER_ID_SHIFT;
			int pointerId=event.getPointerId(pointerIndex);
			TouchEvent touchEvent;
			
			switch(action){
			case MotionEvent.ACTION_DOWN:
			case MotionEvent.ACTION_POINTER_DOWN:
				touchEvent=touchEventPool.newObject();
				touchEvent.type=TouchEvent.TOUCH_DOWN;
				touchEvent.pointer=pointerId;
				touchEvent.x=touchX[pointerId]=(int)(event.getX(pointerIndex)*scaleX);
				touchEvent.y=touchY[pointerId]=(int)(event.getY(pointerIndex)*scaleY);
				isTouched[pointerId]=true;
				touchEventsBuffer.add(touchEvent);
				break;
				
			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_POINTER_UP:
			case MotionEvent.ACTION_CANCEL:
				touchEvent=touchEventPool.newObject();
				touchEvent.type=TouchEvent.TOUCH_UP;
				touchEvent.pointer=pointerId;
				touchEvent.x=touchX[pointerId]=(int)(event.getX(pointerIndex)*scaleX);
				touchEvent.y=touchY[pointerId]=(int)(event.getY(pointerIndex)*scaleY);
				isTouched[pointerId]=false;
				touchEventsBuffer.add(touchEvent);
				break;
				
			case MotionEvent.ACTION_MOVE:
				int pointerCount=event.getPointerCount();
				for(int i=0;i<pointerCount;i++){
					pointerIndex=i;
					pointerId=event.getPointerId(pointerIndex);
					
					touchEvent=touchEventPool.newObject();
					touchEvent.type=TouchEvent.TOUCH_DRAGGED;
					touchEvent.pointer=pointerId;
					touchEvent.x=touchX[pointerId]=(int)(event.getX(pointerIndex)*scaleX);
					touchEvent.y=touchY[pointerId]=(int)(event.getY(pointerIndex)*scaleY);
					touchEventsBuffer.add(touchEvent);
				}
				break;
			}
		}
		return true;
	}

}

 

最后是关于键盘输入的KeyboardHandler

 

public class KeyboardHandler implements OnKeyListener {
	boolean[] pressedKeys=new boolean[128];//KEYCODE正好是0-127
	Pool<KeyEvent> keyEventPool;
	List<KeyEvent> keyEventsBuffer=new ArrayList<KeyEvent>();
	List<KeyEvent> keyEvents=new ArrayList<KeyEvent>();
	
	public KeyboardHandler(View view){
		PoolObjectFactory<KeyEvent> factory=new PoolObjectFactory<KeyEvent>(){
			@Override
			public KeyEvent createObject() {
				return new KeyEvent();
			}
		};
		keyEventPool = new Pool<KeyEvent>(factory,100);
		view.setOnKeyListener(this);
		view.setFocusableInTouchMode(true);
		view.requestFocus();
	}
	@Override
	public boolean onKey(View v, int keyCode, android.view.KeyEvent event) {
		if(event.getAction()==android.view.KeyEvent.ACTION_MULTIPLE){
			return false;
		}
		
		synchronized (this) {
			KeyEvent keyEvent=keyEventPool.newObject();
			keyEvent.keyCode=keyCode;
			keyEvent.keyChar=(char)event.getUnicodeChar();
			if(event.getAction()==android.view.KeyEvent.ACTION_DOWN){
				keyEvent.type=KeyEvent.KEY_DOWN;
				if(keyCode>0&&keyCode<127){
					pressedKeys[keyCode]=true;
				}
			}
			if(event.getAction()==android.view.KeyEvent.ACTION_UP){
				keyEvent.type=KeyEvent.KEY_UP;
				if(keyCode>0&&keyCode<127){
					pressedKeys[keyCode]=false;
				}
			}
			keyEventsBuffer.add(keyEvent);
		}
		return false;
	}
	
	public boolean isKeyPressed(int keyCode){
		if(keyCode<0||keyCode>127){
			return false;
		}
		return pressedKeys[keyCode];
	}
	
	public List<KeyEvent> getKeyEvents(){
		synchronized (this) {
			int len=keyEvents.size();
			for(int i=0;i<len;i++){
				keyEventPool.free(keyEvents.get(i));
			}
			keyEvents.clear();
			keyEvents.addAll(keyEventsBuffer);
			keyEventsBuffer.clear();
			return keyEvents;
		}
	}
}

 

可以看到的是在触控和键盘中,有一个新的类Pool,这是我们自己定义的一个新类,他的作用是对所有的处理动作做出一个缓存

 

import java.util.ArrayList;
import java.util.List;

import com.cookie.androidgames.framework.Input.TouchEvent;

public class Pool<T> {
	public interface PoolObjectFactory<T>{
		public T createObject();
	}
	
	private final List<T> freeObjects;
	private final PoolObjectFactory<T> factory;
	private final int maxSize;
	
	public Pool(PoolObjectFactory<T> factory,int maxSize){
		this.factory=factory;
		this.maxSize=maxSize;
		this.freeObjects=new ArrayList<T>(maxSize);
	}
	
	public T newObject(){
		T object=null;
		if(freeObjects.size()==0){
			object=factory.createObject();
		}else{
			object=freeObjects.remove(freeObjects.size()-1);
		}
		return object;
	}
	
	public void free(T object){
		if(freeObjects.size()<maxSize){
			freeObjects.add(object);
		}
	}
	
/*	用法示例:

	PoolObjectFactory<TouchEvent> factory=new PoolObjectFactory<TouchEvent>() {
		@Override
		public TouchEvent createObject() {
			return new TouchEvent();
		}
	};
	Pool<TouchEvent> touchEventPool=new Pool<T>(factory, 50);
	TouchEvent touchEvent=touchEventPool.newObject();
	..do Something here..
	touchEventPool.free(touchEvent);
	
*/
}

 这是非常精妙的一个类,简单的说就是他规定了一个固定大小的事件缓冲池,而所有的动作都被记录在这个缓存池中,每次产生一个新的动作,并不会被立即执行,而是被放入缓冲池,如果缓冲池已满,那么会从中移除之前的操作,这样就保证了事件处理数量的上限,而不会造成同一时间内事件过多却由于一些原因得不到及时处理的问题

 

分享到:
评论

相关推荐

    python入门-30.寻找列表中只出现一次的数字-寻找单身狗.py

    python入门-30.寻找列表中只出现一次的数字——寻找单身狗.py

    布尔教育linux优化笔记

    linux优化笔记,配套视频:https://www.bilibili.com/list/474327672?sid=4496133&spm_id_from=333.999.0.0&desc=1

    知识付费系统-直播+讲师入驻+课程售卖+商城系统-v2.1.9版本搭建以及资源分享下载

    知识付费系统-直播+讲师入驻+课程售卖+商城系统-v2.1.9版本搭建以及资源分享下载,CRMEB知识付费分销与直播营销系统是由西安众邦科技自主开发的一款在线教育平台,该系统不仅拥有独立的知识产权,还采用了先进的ThinkPhp5.0框架和Vue前端技术栈,集成了在线直播教学及课程分销等多种功能,旨在为用户提供全方位的学习体验,默认解压密码youyacaocom

    美妆神域-JAVA-基于springBoot美妆神域设计与实现

    美妆神域-JAVA-基于springBoot美妆神域设计与实现

    原生js制作Google粘土logo动画涂鸦代码.zip

    原生js制作Google粘土logo动画涂鸦代码.zip

    golin 扫描工具使用, 检查系统漏洞、web程序漏洞

    golin 扫描工具使用, 检查系统漏洞、web程序漏洞

    原生态纯js图片网格鼠标悬停放大显示特效代码下载.zip

    原生态纯js图片网格鼠标悬停放大显示特效代码下载.zip

    用AWLUM进行灰色编码2^2n-QAM调制的精确率Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    去水印web端独立版web

    去水印web端独立版web

    原生js制作左侧浮动可折叠在线客服代码.zip

    原生js制作左侧浮动可折叠在线客服代码.zip

    Chrome 谷歌浏览器下载

    Chrome 谷歌浏览器下载

    亲测全新完整版H5商城系统源码 附教程

    全新完整版H5商城系统源码 自己花钱买的,亲测可用,需要自行下载 H5商城系统设置是实现商城基本功能的核心部分,涵盖了从网站配置、短信和支付配置,到商品、工单、订单、分站和提现管理等多个模块的设置。以下是详细的设置指南,帮助您快速上手并高效管理商城系统。 测试环境:Nginx+PHP7.0+MySQL5.6 1. 网站配置 设置商城名称、LOGO、标题、联系方式和SEO关键词等,确保商城专业和易于搜索。 2. 短信配置 配置短信接口和模板,用于发送订单通知、验证码等,提升用户体验。 3. 支付接口配置 配置微信、支付宝等支付接口,填写API密钥和回调地址,确保支付流畅。 4. 商品分类管理 对商品进行分类和排序,设置分类名称和图标,便于用户查找商品。 5. 商品管理 添加和管理商品信息、规格、图片等,确保商品信息准确丰富。 6. 工单管理 查看和回复用户工单,记录售后问题,提升用户服务质量。 7. 订单管理 查看订单详情,更新订单状态,支持批量导出,方便订单跟踪。 8. 分站管理 创建不同区域分站,设置权限,统一管理各区域市场。 9. 提现管理

    短信3.141592672893982398674234

    apk安装包

    原生js选项卡插件自定义图片滑动选项卡切换.zip

    原生js选项卡插件自定义图片滑动选项卡切换.zip

    1-宗教信息佛教佛寺寺庙庵堂相关数据-社科数据.zip

    宗教信息佛教佛寺寺庙庵堂相关数据集提供了全国各个地区省市县各个佛教寺庙的详细信息。这些数据不仅包括寺庙的名称和负责人姓名,还涵盖了所属省份、地级市、区县、具体地址、建立日期以及支派类别等关键信息。该数据集整理了超过3万条样本,为研究中国佛教寺庙的分布、历史和文化提供了丰富的第一手资料。这些信息有助于了解佛教在中国的传播和发展,以及寺庙在社会和文化中的作用。数据的整理和提供,对于宗教学、社会学、历史学和文化研究等领域的学者来说,是一个宝贵的资源。

    线性电阻网络的等效电阻计算Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    简单的 Python 版本管理.zip

    简单的 Python 版本管理pyenvpyenv 可让您轻松在多个 Python 版本之间切换。它简单、不引人注目,并遵循 UNIX 传统,即使用单一用途的工具来做好一件事。该项目由rbenv和 ruby​​-build分叉而来,并针对 Python 进行了修改。pyenv 的作用是什么......允许您根据每个用户更改全局 Python 版本。为每个项目的 Python 版本提供支持。允许您使用环境变量覆盖 Python 版本。一次搜索多个 Python 版本的命令。这可能有助于使用tox跨 Python 版本进行测试。与 pythonbrew 和 pythonz 相比,pyenv没有……依赖于Python本身。pyenv由纯shell脚本制作。不存在Python的引导问题。需要加载到你的 shell 中。相反,pyenv 的 shim 方法通过向你的 中添加目录来工作PATH。管理虚拟环境。当然,你可以自己创建虚拟环境 ,或者使用pyenv-virtualenv 来自动化该过程。目录安装获取 PyenvLinux/UNIX自动安装程序基本

    Notepad-v2.20工具,是替代Notepad++的首选工具

    Notepad-v2.20工具,是替代Notepad++的首选工具

    原生js随机图片拖拽排序代码.zip

    原生js随机图片拖拽排序代码.zip

    更快、更好、更稳定的Redis桌面(GUI)管理客户端,兼容Windows、Mac、Linux,性能出众,轻松加载海量键值

    更快、更好、更稳定的Redis桌面(GUI)管理客户端,兼容Windows、Mac、Linux,性能出众,轻松加载海量键值

Global site tag (gtag.js) - Google Analytics