標籤:android 貪吃蛇
在上一篇《是男人就下100層【第四層】——Crazy貪吃蛇(1)》中我們讓貪吃蛇移動了起來,接下來我們來實現讓貪吃蛇可以繞著手機螢幕邊線移動並且可以改變方向
一、添加狀態並修改代碼首先我們來用另外一種方式實現上一版本中的重新整理介面,在Crazy貪吃蛇(1)中我們自訂了一個線程每隔1s鐘重新整理介面,線上程中我們使用了postInvalidate()方法通知主線程重繪介面,我們開啟View的原始碼看看到底是如何通知主線程的,原代碼如下:
public void postInvalidate(int left, int top, int right, int bottom) { postInvalidateDelayed(0, left, top, right, bottom); } /** * Cause an invalidate to happen on a subsequent cycle through the event * loop. Waits for the specified amount of time. * * @param delayMilliseconds the duration in milliseconds to delay the * invalidation by */ public void postInvalidateDelayed(long delayMilliseconds) { // We try only with the AttachInfo because there‘s no point in invalidating // if we are not attached to our window if (mAttachInfo != null) { Message msg = Message.obtain(); msg.what = AttachInfo.INVALIDATE_MSG; msg.obj = this; mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds); } } /** * Cause an invalidate of the specified area to happen on a subsequent cycle * through the event loop. Waits for the specified amount of time. * * @param delayMilliseconds the duration in milliseconds to delay the * invalidation by * @param left The left coordinate of the rectangle to invalidate. * @param top The top coordinate of the rectangle to invalidate. * @param right The right coordinate of the rectangle to invalidate. * @param bottom The bottom coordinate of the rectangle to invalidate. */ public void postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom) { // We try only with the AttachInfo because there‘s no point in invalidating // if we are not attached to our window if (mAttachInfo != null) { final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire(); info.target = this; info.left = left; info.top = top; info.right = right; info.bottom = bottom; final Message msg = Message.obtain(); msg.what = AttachInfo.INVALIDATE_RECT_MSG; msg.obj = info; mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds); } }從上面原始碼中我們可以看到最後一句代碼mAttachInfo.mHandler.sendMessageDelayed(msg, delayMillisecods),原來也是通過Handler來實現介面重新整理的,既然是這樣我們就將我們的代碼修改如下:建立一個RefreshHandler類
class RefreshHandler extends Handler{ @Override public void handleMessage(Message msg) { MySnake.this.update(); MySnake.this.invalidate(); } public void sleep(long delayMillis) {this.removeMessages(0);sendMessageDelayed(obtainMessage(0), delayMillis);} }定義了遊戲中的四種狀態
private enum State{ READY, //就緒 PAUSE, //暫停 RUNNING, //運行 LOSE //失敗 }
private void update(){ if(currentState == State.RUNNING){move();mRefreshHandler.sleep(1000); } }我們再來看看上個版本中使蛇移動的核心代碼:
case LEFT: /*for(int i=0; i<boxs.size(); i++){ box = boxs.get(i); box.setX(box.getX() - boxSize); } */ boxs.add(0, new Box(boxs.get(0).getX() - boxSize, 0)); boxs.remove(boxs.size() - 1); break; case RIGHT: /* for(int i=0; i<boxs.size(); i++){ box = boxs.get(i); box.setX(box.getX() + boxSize); } */ boxs.add(new Box(boxs.get(boxs.size() - 1).getX() + boxSize, 0)); boxs.remove(0); break; 我們不用遍曆每一個方塊來實現蛇的移動,我們只需要去改變蛇首和蛇未即可實現。
修改後的MySnake.java檔案
package com.example.crazysnake; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.os.Handler;import android.os.Message;import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; /** * CSDN部落格:http://blog.csdn.net/dawanganban * @author 陽光小強 */public class MySnake extends View { private Paint paint; private RectF rect; private int boxSize = 30; // private SnakeThread snakeThread; private List<Box> boxs = new ArrayList<Box>(); private static final int[] colors = { Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW }; private enum Derectory{ LEFT, RIGHT, TOP, BOTTOM; } private enum State{ READY, //就緒 PAUSE, //暫停 RUNNING, //運行 LOSE //失敗 } private Derectory currentDerect = Derectory.RIGHT; private State currentState = State.PAUSE; private RefreshHandler mRefreshHandler = new RefreshHandler(); class RefreshHandler extends Handler{ @Override public void handleMessage(Message msg) { MySnake.this.update(); MySnake.this.invalidate(); } public void sleep(long delayMillis) {this.removeMessages(0);sendMessageDelayed(obtainMessage(0), delayMillis);} } public MySnake(Context context, AttributeSet attrs) { super(context, attrs); paint = new Paint(); rect = new RectF(); initData(); //startThread(); } /* public void startThread(){ if(snakeThread == null){ snakeThread = new SnakeThread(); snakeThread.start(); } } */ private void update(){ if(currentState == State.RUNNING){move();mRefreshHandler.sleep(1000); } } private void initData(){ Box box; for(int i=0; i<10; i++){ box = new Box(i*boxSize, 0); boxs.add(box); } } private float mDownX; private float mDownY; @Override public boolean onTouchEvent(MotionEvent event) { System.out.println("onTouch"); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mDownX = event.getX(); mDownY = event.getY(); break; case MotionEvent.ACTION_UP: float disX = event.getX() - mDownX; float disY = event.getY() - mDownY; System.out.println("disX = " + disX); System.out.println("dixY = " + disY); if(Math.abs(disX) > Math.abs(disY)){ if(disX > 0){ if(currentState != State.RUNNING){ currentState = State.RUNNING; update(); } currentDerect = Derectory.RIGHT; }else{ currentDerect = Derectory.LEFT; } }else{ if(disY > 0){ currentDerect = Derectory.BOTTOM; }else{ currentDerect = Derectory.TOP; } } break; } return true; } /* private class SnakeThread extends Thread{ private boolean stoped = false; @Override public void run() { while(!stoped){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } move(); postInvalidate(); } } } */ private void move(){ Box box; //判斷邊界條件 if(boxs.get(0).getX() - boxSize < 0) { currentDerect = Derectory.RIGHT; } if(boxs.get(boxs.size() - 1).getX() + 2 * boxSize > getWidth()){ currentDerect = Derectory.LEFT; } switch (currentDerect) { case LEFT: /*for(int i=0; i<boxs.size(); i++){ box = boxs.get(i); box.setX(box.getX() - boxSize); } */ boxs.add(0, new Box(boxs.get(0).getX() - boxSize, 0)); boxs.remove(boxs.size() - 1); break; case RIGHT: /* for(int i=0; i<boxs.size(); i++){ box = boxs.get(i); box.setX(box.getX() + boxSize); } */ boxs.add(new Box(boxs.get(boxs.size() - 1).getX() + boxSize, 0)); boxs.remove(0); break; case TOP: break; case BOTTOM: break; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for(int i=0; i<boxs.size(); i++){ paint.setColor(colors[i % colors.length]); rect.set(boxs.get(i).getX(), boxs.get(i).getY(), boxs.get(i).getX() + boxSize, boxSize); canvas.drawRect(rect, paint); } } }二、實現繞手機邊界移動的貪吃蛇先看看實現的效果:實現代碼如下:
package com.example.crazysnake; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.os.Handler;import android.os.Message;import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; /** * CSDN部落格:http://blog.csdn.net/dawanganban * @author 陽光小強 */public class MySnake extends View { private Paint paint; private Paint textPaint; private RectF rect; private static int boxSize = 40; private static int xMaxBoxCount; //x軸方向最多的box數量private static int yMaxBoxCount; //y軸方向最多的box數量 private List<Box> boxs = new ArrayList<Box>(); private static final int[] colors = { Color.RED, Color.BLUE, Color.GRAY, Color.YELLOW }; private enum Derectory{ LEFT, RIGHT, TOP, BOTTOM; } private enum State{ READY, //就緒 PAUSE, //暫停 RUNNING, //運行 LOSE //失敗 } private Derectory currentDerect = Derectory.LEFT; private State currentState = State.READY; private RefreshHandler mRefreshHandler = new RefreshHandler(); class RefreshHandler extends Handler{ @Override public void handleMessage(Message msg) { MySnake.this.update(); MySnake.this.invalidate(); } public void sleep(long delayMillis) {this.removeMessages(0);sendMessageDelayed(obtainMessage(0), delayMillis);} } public MySnake(Context context, AttributeSet attrs) { super(context, attrs); paint = new Paint(); textPaint = new Paint(); textPaint.setColor(Color.RED); textPaint.setTextSize(80); rect = new RectF(); initData(); } private void update(){ if(currentState == State.RUNNING){move();mRefreshHandler.sleep(150); } } private void initData(){ Box box; for(int i=5; i<10; i++){ box = new Box(i, 0); boxs.add(box); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); xMaxBoxCount = (int) Math.floor(w / boxSize);yMaxBoxCount = (int) Math.floor(h / boxSize); } private float mDownX; private float mDownY; @Override public boolean onTouchEvent(MotionEvent event) { System.out.println("onTouch"); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mDownX = event.getX(); mDownY = event.getY(); break; case MotionEvent.ACTION_UP: float disX = event.getX() - mDownX; float disY = event.getY() - mDownY; System.out.println("disX = " + disX); System.out.println("dixY = " + disY); if(Math.abs(disX) > Math.abs(disY)){ if(disX > 0){ // currentDerect = Derectory.RIGHT; }else{ if(currentState != State.RUNNING){ currentState = State.RUNNING; currentDerect = Derectory.LEFT; update(); } } }else{ if(disY > 0){ // currentDerect = Derectory.BOTTOM; }else{ // currentDerect = Derectory.TOP; } } break; } return true; } private void move(){ Box box; if(currentDerect == Derectory.LEFT && boxs.get(0).getX() <= 0){ currentDerect = Derectory.BOTTOM; } if(currentDerect == Derectory.BOTTOM && boxs.get(0).getY() >= yMaxBoxCount -1){ currentDerect = Derectory.RIGHT; } if(currentDerect == Derectory.RIGHT && boxs.get(0).getX() >= xMaxBoxCount - 1){ currentDerect = Derectory.TOP; } if(currentDerect == Derectory.TOP && boxs.get(0).getY() <= 0){ currentDerect = Derectory.LEFT; } switch (currentDerect) { case LEFT: boxs.add(0, new Box(boxs.get(0).getX() - 1, boxs.get(0).getY())); boxs.remove(boxs.size() - 1); break; case RIGHT: boxs.add(0, new Box(boxs.get(0).getX() + 1, boxs.get(0).getY())); boxs.remove(boxs.size() - 1); break; case TOP: boxs.add(0, new Box(boxs.get(0).getX(), boxs.get(0).getY() - 1)); boxs.remove(boxs.size() - 1); break; case BOTTOM: boxs.add(0, new Box(boxs.get(0).getX(), boxs.get(0).getY() + 1)); boxs.remove(boxs.size() - 1); break; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for(int i=0; i<boxs.size(); i++){ paint.setColor(colors[i % colors.length]); rect.set(boxs.get(i).getX() * boxSize, boxs.get(i).getY() * boxSize, (boxs.get(i).getX() + 1) * boxSize, (boxs.get(i).getY() + 1) * boxSize); canvas.drawRect(rect, paint); } if(currentState == State.READY){ canvas.drawText("請向左滑動", (xMaxBoxCount * boxSize - textPaint.measureText("請向左滑動")) / 2, xMaxBoxCount * boxSize / 2, textPaint); } } }
源碼下載說明:前一個版本在GitHub上,這一版我將該項目上傳到了CSDN的CODE上面,可以使用SVN或Git下載
CODE源碼:https://code.csdn.net/lxq_xsyu/crazysnakeCSDN:http://download.csdn.net/detail/lxq_xsyu/7629435