Android游戏之输入类设计(传感器,键盘,触摸点)
1、基础知识:
A. SensorEventListener传感器事件监听
http://developer.android.com/reference/android/hardware/SensorEventListener.html
Class Overview
--------------------------------------------------------------------------------
Used for receiving notifications from the SensorManager when sensor values have changed.
Summary
--------------------------------------------------------------------------------
Public Methods
abstract void onAccuracyChanged(Sensor sensor, int accuracy)
Called when the accuracy of the registered sensor has changed.
abstract void onSensorChanged(SensorEvent event)
Called when sensor values have changed.
B. OnKeyListener键盘监听
http://developer.android.com/reference/android/view/View.OnKeyListener.html
Class Overview
--------------------------------------------------------------------------------
Interface definition for a callback to be invoked when a hardware key event is dispatched to this view. The callback will be invoked before the key event is given to the view. This is only useful for hardware keyboards; a software input method has no obligation to trigger this listener.
Summary
--------------------------------------------------------------------------------
Public Methods
abstract boolean onKey(View v, int keyCode, KeyEvent event)
Called when a hardware key is dispatched to a view.
C. OnTouchListener触摸监听
http://developer.android.com/reference/android/view/View.OnTouchListener.html
Class Overview
--------------------------------------------------------------------------------
Interface definition for a callback to be invoked when a touch event is dispatched to this view. The callback will be invoked before the touch event is given to the view.
Summary
--------------------------------------------------------------------------------
Public Methods
abstract boolean onTouch(View v, MotionEvent event)
Called when a touch event is dispatched to a view.
2、设计3个输入类(传感器,键盘,触摸点)AccelerometerHandler,KeyboardHandler,touchHandler
package com.badlogic.androidgames.framework.impl; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; 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 accelerometer = manager.getSensorList( Sensor.TYPE_ACCELEROMETER).get(0); manager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // nothing to do here } @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; } }
package com.badlogic.androidgames.framework.impl; import java.util.ArrayList; import java.util.List; import android.view.View; import android.view.View.OnKeyListener; import com.badlogic.androidgames.framework.Input.KeyEvent; import com.badlogic.androidgames.framework.Pool; import com.badlogic.androidgames.framework.Pool.PoolObjectFactory; public class KeyboardHandler implements OnKeyListener { boolean[] pressedKeys = new boolean[128]; 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; } } }
package com.badlogic.androidgames.framework.impl; import java.util.List; import android.view.View.OnTouchListener; import com.badlogic.androidgames.framework.Input.TouchEvent; public interface TouchHandler extends OnTouchListener { public boolean isTouchDown(int pointer); public int getTouchX(int pointer); public int getTouchY(int pointer); public List<TouchEvent> getTouchEvents(); }
3. KeyboardHandler类引入了一个PoolObjectFactory<T>,T对象池工厂类
package com.badlogic.androidgames.framework; import java.util.ArrayList; import java.util.List; 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); } }
4. 扩展TouchHandler类为单点触摸类SingleTouchHandler和多点触摸类MultiTouchHandler
package com.badlogic.androidgames.framework.impl; import java.util.ArrayList; import java.util.List; import android.view.MotionEvent; import android.view.View; import com.badlogic.androidgames.framework.Pool; import com.badlogic.androidgames.framework.Input.TouchEvent; import com.badlogic.androidgames.framework.Pool.PoolObjectFactory; 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 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; } } @Override public boolean isTouchDown(int pointer) { synchronized(this) { if(pointer == 0) return isTouched; else return false; } } @Override public int getTouchX(int pointer) { synchronized(this) { return touchX; } } @Override public int getTouchY(int pointer) { synchronized(this) { return touchY; } } @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; } } }
package com.badlogic.androidgames.framework.impl; import java.util.ArrayList; import java.util.List; import android.view.MotionEvent; import android.view.View; import com.badlogic.androidgames.framework.Input.TouchEvent; import com.badlogic.androidgames.framework.Pool; import com.badlogic.androidgames.framework.Pool.PoolObjectFactory; 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 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; } } @Override public boolean isTouchDown(int pointer) { synchronized (this) { if (pointer < 0 || pointer >= 20) return false; else return isTouched[pointer]; } } @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 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; } } }
5、设计AndroidInput类,实现Input接口,由传感器AccelerometerHandler,键盘KeyboardHandler,触摸点touchHandler组成
package com.badlogic.androidgames.framework; import java.util.List; public interface Input { public static class KeyEvent { public static final int KEY_DOWN = 0; public static final int KEY_UP = 1; public int type; public int keyCode; public char keyChar; public String toString() { StringBuilder builder = new StringBuilder(); if (type == KEY_DOWN) builder.append("key down, "); else builder.append("key up, "); builder.append(keyCode); builder.append(","); builder.append(keyChar); return builder.toString(); } } public static class TouchEvent { public static final int TOUCH_DOWN = 0; public static final int TOUCH_UP = 1; public static final int TOUCH_DRAGGED = 2; public int type; public int x, y; public int pointer; public String toString() { StringBuilder builder = new StringBuilder(); if (type == TOUCH_DOWN) builder.append("touch down, "); else if (type == TOUCH_DRAGGED) builder.append("touch dragged, "); else builder.append("touch up, "); builder.append(pointer); builder.append(","); builder.append(x); builder.append(","); builder.append(y); return builder.toString(); } } public boolean isKeyPressed(int keyCode); public boolean isTouchDown(int pointer); public int getTouchX(int pointer); public int getTouchY(int pointer); public float getAccelX(); public float getAccelY(); public float getAccelZ(); public List<KeyEvent> getKeyEvents(); public List<TouchEvent> getTouchEvents(); }
package com.badlogic.androidgames.framework.impl; import java.util.List; import android.content.Context; import android.os.Build.VERSION; import android.view.View; import com.badlogic.androidgames.framework.Input; 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 boolean isKeyPressed(int keyCode) { return keyHandler.isKeyPressed(keyCode); } @Override public boolean isTouchDown(int pointer) { return touchHandler.isTouchDown(pointer); } @Override public int getTouchX(int pointer) { return touchHandler.getTouchX(pointer); } @Override public int getTouchY(int pointer) { return touchHandler.getTouchY(pointer); } @Override public float getAccelX() { return accelHandler.getAccelX(); } @Override public float getAccelY() { return accelHandler.getAccelY(); } @Override public float getAccelZ() { return accelHandler.getAccelZ(); } @Override public List<TouchEvent> getTouchEvents() { return touchHandler.getTouchEvents(); } @Override public List<KeyEvent> getKeyEvents() { return keyHandler.getKeyEvents(); } }
本文浅述了“beginning-android-games”书本的相关基础知识和相关类的设计分析,
书本和源码:http://download.csdn.net/detail/yangzhenping/8420261
本篇中的类实现来自“beginning-android-games\ch07-gl-basics”