package com.hitfm.improve; import java.util.ArrayList; import java.util.List; import java.util.Random; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.view.KeyEvent; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import android.view.animation.Animation; import android.widget.Toast; /** * @author Himi */ public class SurfaceView_Cube extends SurfaceView implements Callback, Runnable { //标记程序是否初始化 private boolean init = false; //图片大小,pix private final static int mTileSize = 36; //敌方图片数量 private final static int mEnemyCount = 26; //sprite运动状态 private final static int STOP = 0; private final static int LEFT = -1; private final static int RIGTH = 1; //程序运行状态 private final static int END = 0; private final static int RUN = 1; private final static int PAUSE = 2; private int mstate = END; //系统变量 private SurfaceHolder mSurfaceHolder; private Thread mMapThread; private Canvas mCanvas; private Paint mPaint; private Bitmap[] bitmaps; //系统参数,屏幕宽高,图片行列数量和偏移 private int mScreenW, mScreenH; private int mXTile, mYTile; private int mXOffset, mYOffset; //存储图片所以,列(行) private ArrayList<int[]> mTileGrid; //第一张图片索引 private int imgIndex = 0x7f020000; //随机产生敌机 private Random random = new Random(); //sprite private Sprite mSprite; //存储子弹参数 private List<Point> mBullet = new ArrayList<Point>(); //sprite和bullet图片索引 private final static int mSpriteIndex = 27; private final static int mBulletIndex = 27; //表示此坐标无图片 private final static int NOTHING = 0; //线控按键索引 private final static int KEY_FIRE = KeyEvent.KEYCODE_HEADSETHOOK; private final static int KEY_LEFT = KeyEvent.KEYCODE_MEDIA_PREVIOUS; private final static int KEY_RIGHT = KeyEvent.KEYCODE_MEDIA_NEXT; //触发长按事件的时间 private final static int LONG_PRESS_TIME = 500; //标记屏幕更新时间 private long lastTime = 0; //现在时间 private long now = 0; //sprite的更新间隔 private int mDelay = 10; //子弹和敌机的更新间隔 private int mEnemyAndBulletDelay=mDelay * 150; public SurfaceView_Cube(Context context) { super(context); mMapThread = new Thread(this); mSurfaceHolder = this.getHolder(); mSurfaceHolder.addCallback(this); mPaint = new Paint(); //反锯齿 mPaint.setAntiAlias(true); //屏幕常亮 this.setKeepScreenOn(true); } @Override public void startAnimation(Animation animation) { super.startAnimation(animation); } /** * 屏幕初始化时做的准备 */ @Override public void surfaceCreated(SurfaceHolder holder) { initScreenPrams(); loadTiles(); initSprite(); Toast.makeText(getContext(), R.string.start, Toast.LENGTH_SHORT).show(); } /** * 初始化sprite,在屏幕最后一行的中间位置 */ private void initSprite() { mSprite = new Sprite((mXTile - 1) / 2, mYTile - 1); mSprite.setDirection(STOP); } /** * 加载所有图片,0-25为敌机,26为sprite */ private void loadTiles() { bitmaps = new Bitmap[mEnemyCount + 1]; for (int i = 0; i < mEnemyCount + 1; i++) { bitmaps[i] = BitmapFactory.decodeResource(this.getResources(), imgIndex++); bitmaps[i] = resizeImage(bitmaps[i], mTileSize, mTileSize); } } /** * 初始化屏幕参数 */ private void initScreenPrams() { mScreenW = this.getWidth(); mScreenH = this.getHeight(); mXTile = mScreenW / mTileSize; mYTile = mScreenH / mTileSize; mXOffset = (mScreenW % mTileSize) / 2; mYOffset = (mScreenH % mTileSize) / 2; initTileGrid(); } /** * 初始化屏幕图片索引矩阵 */ private void initTileGrid() { int[] tempXTile; mTileGrid = new ArrayList<int[]>(); for (int i = 0; i < mYTile; i++) { tempXTile = new int[mXTile]; mTileGrid.add(tempXTile); } } public void run() { while (true) { if (mstate == END || mstate == PAUSE) { continue; } try { mCanvas = mSurfaceHolder.lockCanvas(); mCanvas.drawColor(Color.WHITE); updateSprite(); updateEnemyAndBullet(); drawAll(); Thread.sleep(mDelay); } catch (Exception ex) { ex.printStackTrace(); } finally { if (mCanvas != null) { mSurfaceHolder.unlockCanvasAndPost(mCanvas); } } } } /** * 绘制屏幕 */ private void drawAll() { int[] row; for (int i = 0; i < mYTile; i++) { row = mTileGrid.get(i); for (int j = 0; j < mXTile; j++) { if (row[j] != NOTHING) { drawBitmap(row[j], j, i, mPaint); } } } } /** * 清除所有子弹 */ private void clearBullet() { int x, y; for (int i = 0; i < mBullet.size(); i++) { x = mBullet.get(i).x; y = mBullet.get(i).y; if (y == mYTile - 1) { continue; } mTileGrid.get(y)[x] = NOTHING; } } /** * 更新所有子弹位置 */ private void updateBullet() { int x, y; int[] removeIndex = new int[mBullet.size()]; if (!mBullet.isEmpty()) { for (int i = 0; i < mBullet.size(); i++) { x = mBullet.get(i).x; y = mBullet.get(i).y; // 子弹到达最顶部 if (y == 0) { removeIndex[i] = 1; } // 子弹已经遇到障碍物 else if (mTileGrid.get(y)[x] != NOTHING && mTileGrid.get(y)[x] != mBulletIndex) { removeIndex[i] = 1; mTileGrid.get(y)[x] = NOTHING; } // 子弹即将遇到障碍物 else if (mTileGrid.get(y - 1)[x] != NOTHING && mTileGrid.get(y - 1)[x] != mBulletIndex) { removeIndex[i] = 1; mTileGrid.get(y - 1)[x] = NOTHING; } // 将子弹上移 else if (mTileGrid.get(y - 1)[x] == NOTHING) { mBullet.set(i, new Point(x, y - 1)); mTileGrid.get(y - 1)[x] = mBulletIndex; } } //将子弹从索引中移除 for (int i = removeIndex.length - 1; i >= 0; i--) { if (removeIndex[i] == 1) { mBullet.remove(i); } } } } /** * 更新sprite位置 */ private void updateSprite() { int oldX = mSprite.getX(); int newX = oldX + mSprite.getDirection(); if (newX < 0 || newX >= mXTile) { newX = oldX; } int y = mYTile - 1; mTileGrid.get(y)[oldX] = NOTHING; mSprite.setXY(newX, y); mTileGrid.get(mTileGrid.size() - 1)[newX] = mSpriteIndex; mSprite.setDirection(STOP); } /** * 在满足更新间隔的要求下更新敌机和子弹位置 */ private void updateEnemyAndBullet() { now = System.currentTimeMillis(); if ((now - lastTime) > (mEnemyAndBulletDelay)) { lastTime = System.currentTimeMillis(); clearBullet(); updateEnemy(); updateBullet(); } } /** * 更新enemy,生成第一行,插入最前面,第二行到倒数第二行依次向下移动,再移除倒数第二行 */ private void updateEnemy() { int randomX, randomEnemyType; int[] newFirstRow = new int[mXTile]; for (int i = 0; i < mXTile / 4;) { randomX = random.nextInt(mXTile); randomEnemyType = random.nextInt(mEnemyCount + 1); if (newFirstRow[randomX] == NOTHING) { newFirstRow[randomX] = randomEnemyType; i++; } } mTileGrid.add(0, newFirstRow); mTileGrid.remove(mTileGrid.size() - 2); } /** * 绘制bitmap * @param bitmapIndex 图片索引 * @param x x轴坐标 * @param y y轴坐标 * @param paint 画笔 */ private void drawBitmap(int bitmapIndex, int x, int y, Paint paint) { if (bitmapIndex >= 1 && bitmapIndex <= mEnemyCount + 1) { mCanvas.drawBitmap(bitmaps[bitmapIndex - 1], mXOffset + x * mTileSize, mYOffset + y * mTileSize, paint); } } /** * 重置图片大小 * @param bitmap 需要被重置的图片 * @param w 新的宽度 * @param h 新的高度 * @return 重置后的图片 */ public static Bitmap resizeImage(Bitmap bitmap, int w, int h) { Bitmap BitmapOrg = bitmap; int width = BitmapOrg.getWidth(); int height = BitmapOrg.getHeight(); int newWidth = w; int newHeight = h; float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width, height, matrix, true); return resizedBitmap; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //第一次按键,初始化线程 if (!init) { mMapThread.start(); } //设置按键方向 setDirection(keyCode); return true; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if ((event.getEventTime() - event.getDownTime()) > LONG_PRESS_TIME) { return this.onKeyLongPress(keyCode, event); } return true; } @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { return false; } /** * 设置按键方向 * @param keyCode */ private void setDirection(int keyCode) { if (!init) { init = true; mstate = RUN; } switch (keyCode) { case KEY_LEFT: mSprite.setDirection(LEFT); break; case KEY_RIGHT: mSprite.setDirection(RIGTH); break; case KEY_FIRE: int xBullet = mSprite.getX(); int yBullet = mSprite.getY(); mBullet.add(new Point(xBullet, yBullet)); mTileGrid.get(yBullet)[xBullet] = mBulletIndex; break; default: break; } } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } public void surfaceDestroyed(SurfaceHolder holder) { } }