It's the next layer for a man. [Layer 4] -- Crazy greedy snakes (2) and crazy greedy snakes
In the previous article "it's a man's next layer [Layer 4] -- Crazy greedy snake (1)", we moved the greedy snake, next, let's make it possible for the snake to move around the cell phone's screen edge and change its direction.
1. Add the status and modify the code. First, we can use another method to refresh the interface in the previous version. (1) we have customized a thread to refresh the interface every 1 s. In the thread, we use the postInvalidate () method to notify the main thread to redraw the interface, open the source code of View to see how the main thread is notified. The original code is as follows:
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); } }From the source code above, we can see the last code mAttachInfo. mHandler. sendMessageDelayed (msg, delayMillisecods), originally implemented interface refresh through Handler. In this case, we modify our code as follows: Create a RefreshHandler class
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);} }Defines four States in the game
Private enum State {READY, // READY for PAUSE, // pause running, // run LOSE // Failed}
private void update(){ if(currentState == State.RUNNING){move();mRefreshHandler.sleep(1000); } }Let's take a look at the core code that moved the snake in the previous version:
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; We don't need to traverse every square to move the snake. We just need to change the first and last of the snakes.
Modified MySnake. java File
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 blog: htt P: // blog.csdn.net/dawanganban * @ author sunshine Xiaoqiang */public class MySnake extends View {private Paint paint; private RectF rect; private int boxSize = 30; // private snkethread; private List <Box> boxs = new ArrayList <Box> (); private static final int [] colors = {Color. RED, Color. BLUE, Color. GREEN, Color. YELLOW}; private enum derecloud {LEFT, RIGHT, TOP, BOTTOM;} private enum State {READY, // Ready for PAUSE, // pause running, // run LOSE // Failed} private derecloud currentDerect = derecloud. 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 (snkethread = null) {snkethread = new snkethread (); snkethread. 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: f Loat 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 = derecloud. RIGHT;} else {currentDerect = derecloud. LEFT ;}} else {if (disY> 0) {currentDerect = derecloud. BOTTOM;} else {currentDerect = derecloud. TOP ;}} break;} return true;}/* private class snkethread 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; // determine the boundary condition if (boxs. get (0 ). getX ()-boxSize <0) {currentDerect = derecloud. RIGHT;} if (boxs. get (boxs. size ()-1 ). getX () + 2 * boxSize> getWidth () {currentDerect = derecloud. 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 );}}}2. Implement a greedy snake that moves around the mobile phone border to see the implementation result first: the implementation code is as follows:
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 blog: htt P: // blog.csdn.net/dawanganban * @ author sunshine Xiaoqiang */public class MySnake extends View {private Paint paint; private Paint textPaint; private RectF rect; private static int boxSize = 40; private static int xMaxBoxCount; // The maximum number of boxes in the X axis direction. private static int yMaxBoxCount; // The maximum number of boxes in the Y axis. private List <box> boxs = new ArrayList <Box> (); private static final int [] colors = {Color. RED, Color. BLUE, Color. GRAY, Col Or. YELLOW}; private enum derecloud {LEFT, RIGHT, TOP, BOTTOM;} private enum State {READY, // READY for PAUSE, // pause running, // run LOSE // Failed} private derecloud currentDerect = derecloud. 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. 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 mD OwnY; @ 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 = derecloud. RIGHT;} else {if (currentState! = State. RUNNING) {currentState = State. RUNNING; currentDerect = derecloud. LEFT; update () ;}}else {if (disY> 0) {// currentDerect = derecloud. BOTTOM;} else {// currentDerect = derecloud. TOP ;}} break;} return true;} private void move () {Box box; if (currentDerect = derecloud. LEFT & boxs. get (0 ). getX () <= 0) {currentDerect = derecloud. BOTTOM;} if (currentDerect = derecloud. BOTTOM & boxs. get (0 ). getY ()> = yMaxBoxCount-1) {currentDerect = derecloud. RIGHT;} if (currentDerect = derecloud. RIGHT & boxs. get (0 ). getX ()> = xMaxBoxCount-1) {currentDerect = derecloud. TOP;} if (currentDerect = derecloud. TOP & boxs. get (0 ). getY () <= 0) {currentDerect = derecloud. 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 ("Slide left", (xMaxBoxCount * boxSize-textPaint. measureText ("Slide left")/2, xMaxBoxCount * boxSize/2, textPaint );}}}
Source CODE download instructions: the previous version is on GitHub. This version uploads the project to the csdn code and can be downloaded using SVN or Git.
CODE source CODE: https://code.csdn.net/lxq_xsyu/crazysnakeCSDN:http://download.csdn.net/detail/lxq_xsyu/7629435