• 是男人就下100层【第四层】——Crazy贪吃蛇(2)


    在上一篇《是男人就下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/crazysnake
    CSDN下载地址:http://download.csdn.net/detail/lxq_xsyu/7629435
  • 相关阅读:
    Java关键字new和newInstance的区别
    关于能提高Java代码可重用性的三个措施
    Java编程技巧—— JDBC编程总结
    Java高质量代码之数组与集合
    ab的压力测试(转)
    利用DOCKER实现云桌面的开发环境初步设想
    时间和日期
    内存流-操作文件的方式操作内存
    获取文件描述符
    流定位
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6468866.html
Copyright © 2020-2023  润新知