游戏规则:大理石圆球(Marble)由于重力加速度移动,当碰到黑色区域判定为输,碰到蓝色区域判定为赢,碰到灰色区域继续移动。
[效果图]
(1)描述迷宫的数据
随着关卡的递增,迷宫样式也会增加复杂度。迷宫的样式是借助文档描述(txt文档)显示出来的。
例如上图样式是由以下的数据绘制出来的:
(2)读取assets文件夹内的txt文件
Android 系统为每个新设计的程序提供了/assets目录,这个目录保存的文件可以打包在程序里。/res 和/assets的不同点是,android不为/assets下的文件生成ID。如果使用/assets下的文件,需要指定文件的路径和文件名。
下面的代码实现了从assets文件夹指定的文件中读取迷宫描述数据,保存至整型数组中。
private static int[] mMazeData;
/** * Load specified maze level. * * @param activity * Activity controlled the maze, we use this load the level data * @param newLevel * Maze level to be loaded. */ void load(Activity activity, int newLevel) { // maze data is stored in the assets folder as level1.txt, level2.txt // etc.... String mLevel = "level" + newLevel + ".txt"; InputStream is = null; try { // construct our maze data array. mMazeData = new int[MAZE_ROWS * MAZE_COLS]; // attempt to load maze data. is = activity.getAssets().open(mLevel); // we need to loop through the input stream and load each tile for // the current maze. for (int i = 0; i < mMazeData.length; i++) { // data is stored in unicode so we need to convert it. mMazeData[i] = Character.getNumericValue(is.read()); // skip the "," and white space in our human readable file. is.read(); is.read(); } } catch (Exception e) { Log.i("Maze", "load exception: " + e); } finally { closeStream(is);
(3)绘图 View Canvas Paint OnDraw
Android绘图操作,通过继承View 实现,在onDraw 函数中实现绘图。invalidate和postInvalidate这两个方法是用来刷新界面的 ,调用这两个方法后,会调用onDraw事件,让界面重绘。
以下代码实现游戏界面的绘制和更新操作,gameTick()是根据加速度传感器获得的坐标值来重新为绘制参数赋值。
@Override public void onDraw(Canvas canvas) { // update our canvas reference. mCanvas = canvas; // clear the screen. mPaint.setColor(Color.WHITE); mCanvas.drawRect(0, 0, mCanvasWidth, mCanvasHeight, mPaint); // simple state machine, draw screen depending on the current state. switch (mCurState) { case GAME_RUNNING: // draw our maze first since everything else appears "on top" of it. mMaze.draw(mCanvas, mPaint); // draw our marble and hud. mMarble.draw(mCanvas, mPaint); // draw hud drawHUD(); break; case GAME_OVER: drawGameOver(); break; case GAME_COMPLETE: drawGameComplete(); break; case GAME_LANDSCAPE: drawLandscapeMode(); break; } gameTick(); }
(4)Activity显示自定义View
确保只在运行状态访问加速度感应器服务。在onResume注册,在
onPause反注册。
“To ensure that you request service updates only while in the Running state, register for updates in onResume()
and unregister in onPause()
.”
public class AmazedActivity extends Activity { // custom view private AmazedView mView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // remove title bar. requestWindowFeature(Window.FEATURE_NO_TITLE); // setup our view, give it focus and display. mView = new AmazedView(getApplicationContext(), this); mView.setFocusable(true); setContentView(mView); } @Override protected void onResume() { super.onResume(); mView.registerListener(); } @Override public void onSaveInstanceState(Bundle icicle) { super.onSaveInstanceState(icicle); mView.unregisterListener(); } }
手机屏幕向上(z轴朝天)水平放置的时侯,(x,y,z)的值分别为(0,0,10);
手机屏幕向下(z轴朝地)水平放置的时侯,(x,y,z)的值分别为(0,0,-10);
手机屏幕向左侧放(x轴朝天)的时候,(x,y,z)的值分别为(10,0,0);
手机竖直(y轴朝天)向上的时候,(x,y,z)的值分别为(0,10,0);
其他的如此类推,规律就是:朝天的就是正数,朝地的就是负数。 利用x,y,z三个值求三角函数,就可以精确检测手机的运动状态了。
以下代码的功能是,获得一个加速度感应器服务的管理者(Manager),创建一个监听(SensorListener)并实现其接口(onSensorChanged) ,这样,当事件触发事,服务管理者就能调用该回调函数(onSensorChanged)了。在这里,回调函数中实现了存储加速度感应坐标的功能。
// http://code.google.com/android/reference/android/hardware/SensorManager.html#SENSOR_ACCELEROMETER // for an explanation on the values reported by SENSOR_ACCELEROMETER. private final SensorListener mSensorAccelerometer = new SensorListener() { // method called whenever new sensor values are reported. public void onSensorChanged(int sensor, float[] values) { // grab the values required to respond to user movement. mAccelX = values[0]; mAccelY = values[1]; mAccelZ = values[2]; } // reports when the accuracy of sensor has change // SENSOR_STATUS_ACCURACY_HIGH = 3 // SENSOR_STATUS_ACCURACY_LOW = 1 // SENSOR_STATUS_ACCURACY_MEDIUM = 2 // SENSOR_STATUS_UNRELIABLE = 0 //calibration required. public void onAccuracyChanged(int sensor, int accuracy) { // currently not used } /** * Custom view constructor. * * @param context * Application context * @param activity * Activity controlling the view */ public AmazedView(Context context, Activity activity) { super(context); ... // setup accelerometer sensor manager. mSensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE); // register our accelerometer so we can receive values. // SENSOR_DELAY_GAME is the recommended rate for games mSensorManager.registerListener(mSensorAccelerometer, SensorManager.SENSOR_ACCELEROMETER, SensorManager.SENSOR_DELAY_GAME); ... }
在OnDraw函数里面,将小球所在的坐标转换为行号和列号,根据行号和列号算出所在的mMazeData数组的索引,求出索引值,1代表输、2代表赢、0代表继续移动。
参考
http://www.pin5i.com/showtopic-android-sensormanager-demo.html