`

《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);
	
*/
}

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

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics