zoukankan      html  css  js  c++  java
  • <Android 应用 之路> 简易贪吃蛇

    最简单的贪吃蛇

    最近想着忙里偷闲写点简单的Android应用,增加一些生活乐趣,由于平时工作主要精力并不是集中在书写apk上,更多的是解决代码问题和维护模块稳定,但是写代码本身是一件比较有趣的事情,因为这个过程是从无到有的。

    名称:贪吃蛇
    开发环境:IntelliJ IDEA 14.0.3
    思路:
    1. 定时刷新界面,因为蛇是不会停止的
    2. 随机产生食物
    3. 蛇体的更新
    4. 蛇体如何出现移动的效果

    缺陷:没有结束,没有碰壁,没有追尾,除非推出(现在知道为什么是最简单的了吧)

    代码分析:
    1. MyActivity, 主要作用就是定时刷新界面,让蛇不停的前进

        private SnakeView mSnakeView;  //填充窗口的View,刷新的对象
        private static final int REFRESH = 1; //定义消息 防止硬编码
        private static final int REFRESHINTERVAL = 300; //刷新的时间间隔
        private boolean isPaused = false; //线程的停止标志位
        private Handler mHandler = new Handler() { //thread handler 消息处理
            @Override
            public void handleMessage(Message msg) {
                // TODO Auto-generated method stub
                super.handleMessage(msg);
                if(msg.arg1 == REFRESH) {
                    if(mSnakeView != null) {
                        mSnakeView.invalidate();
                    }
                }
            }
    
        };
        private Thread mRefreshThread; //用于发送刷新消息的线程
    
        //Activity的onCreate方法
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mSnakeView = new SnakeView(this);  
            setContentView(mSnakeView);
            isPaused = false;
    
            mRefreshThread = new Thread("TimerThread"){
    
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    super.run();
                    while(!isPaused) {
                        Message msg = mHandler.obtainMessage();
                        msg.arg1 = REFRESH;
                        mHandler.sendMessage(msg);
                        try {
                            Thread.sleep(REFRESHINTERVAL); //休眠一段时间后再发送消息刷新界面
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
    
            };
            mRefreshThread.start(); //启动线程
        }
    1. SnakeView ,主游戏界面,蛇体,背景和食物的显示界面
    //自定义View
    public class SnakeView extends View{
        public static final String  TAG = "SnakeView";
    
        private int mWidth;  //view的宽
        private int mHeight; //View的高
    
        private static final int sXOffset = 0 ; 
        private static final int sYOffset = 0 ; // X坐标和Y坐标的偏移量,可以修改来缩小游戏范围
    
        private final int BOXWIDTH = 30; //食物的边长,蛇体的宽度
        private Random mRandom = new Random(); //用于产生随机数
        private Point mFoodPosition; //食物的位置
        private boolean mIsFoodDone = true; //食物是否已经被吃掉
    
        private ArrayList<Point> mSnakeList;  //蛇体可以看做是很多食物组成的
        private Paint mSnakePaint;  //用于画蛇的画笔
        private int mSnakeDirection = 0; //蛇体运动的方向
        private final int UP = 1; 
        private final int DOWN = 2;
        private final int LEFT = 3;
        private final int RIGHT =4;
    
        private Paint mBgPaint;//游戏背景画笔
        private Paint mFoodPaint;//食物画笔
    
    
        public SnakeView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
            mSnakeList = new ArrayList<Point>();
            mSnakePaint = new Paint();
            mSnakePaint.setColor(Color.RED);
            mSnakePaint.setStyle(Paint.Style.FILL_AND_STROKE);
            mSnakeList.add(new Point(500,500));
            mSnakeList.add(new Point(500,530)); //初始化一条丑陋的蛇
    
            mSnakeDirection = RIGHT;
            mIsFoodDone = true;
            mFoodPosition= new Point();
    
            mFoodPaint = new Paint();
            mFoodPaint.setColor(Color.CYAN);
            mFoodPaint.setStyle(Paint.Style.FILL);
    
            mBgPaint = new Paint();
            Paint paint = new Paint();
            paint.setColor(Color.WHITE);   //初始化各种画笔
    
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) { //通过手势来改变蛇体运动方向
            // TODO Auto-generated method stub
    
            int x = (int)(event.getX());
            int y = (int)(event.getY());
            Log.e(TAG, "x =" + x + " y = " + y + " mSnakeDirection = " + mSnakeDirection);
            if(mSnakeDirection == UP || mSnakeDirection == DOWN) {
                if(x < head.x) mSnakeDirection = LEFT;
                if(x > head.x) mSnakeDirection = RIGHT;
            } else if(mSnakeDirection == LEFT || mSnakeDirection == RIGHT) {
                if(y < head.y) mSnakeDirection = UP;
                if(y > head.y) mSnakeDirection= DOWN;
            }
            //Log.e(TAG, "after adjust mSnakeDirection = " + mSnakeDirection);
            return super.onTouchEvent(event);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            //Log.e(TAG ,"onDraw");
            super.onDraw(canvas);
    
            drawBg(canvas, mBgPaint);  //画背景
            drawFood(canvas, mFoodPaint);//画食物
            drawSnake(canvas, mSnakePaint); //画蛇
    
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            // TODO Auto-generated method stub
            super.onSizeChanged(w, h, oldw, oldh);
            mWidth = w;
            mHeight = h;
        }
    
        //画背景 这里通过sXOffset, sYOffset可以实现对蛇活动区域的限制
        private void drawBg(Canvas canvas, Paint paint) {
            canvas.drawColor(Color.WHITE);
            //Rect rect = new Rect(sXOffset, sYOffset, mWidth - sXOffset, mHeight - sYOffset);
            //canvas.drawRect(rect, paint);
        }
    
        //画蛇体
        private void drawSnake(Canvas canvas, Paint paint) {
            for(int i = 0 ; i < mSnakeList.size() ; i++ ) {
                Point point = mSnakeList.get(i);
                Rect rect = new Rect(point.x , point.y , point.x + BOXWIDTH , point.y + BOXWIDTH);
                canvas.drawRect(rect, paint);
            }
            //蛇移动,更新list为下一次刷新做准备
            snakeMove(mSnakeList, mSnakeDirection);
            if(isFoodEaten()) {  //如果吃了食物,长度加1
                mIsFoodDone = true;
            } else {    //如果没有吃食物,由于前进时加了一个 这里删除尾巴,出现移动的效果
                mSnakeList.remove(mSnakeList.size() - 1);
            }
        }
    
        //画食物
        private void drawFood(Canvas canvas, Paint paint) {
            if(mIsFoodDone) {  //只在前一个食物被吃掉的情况下才产生食物
                mFoodPosition.x = mRandom.nextInt(mWidth - 2*sXOffset - BOXWIDTH) + sXOffset ;
                mFoodPosition.y = mRandom.nextInt(mWidth - 2*sYOffset - BOXWIDTH) + sYOffset ;
                mIsFoodDone = false;
            }
            Rect food = new Rect(mFoodPosition.x , mFoodPosition.y , mFoodPosition.x + BOXWIDTH , mFoodPosition.y + BOXWIDTH);
            canvas.drawRect(food, paint);
    
        }
    
        public void snakeMove(ArrayList<Point> list , int direction) {
            //Log.e(TAG," snakeMove ArrayList = " + list.toString());
            Point orighead = list.get(0);
            Point newhead = new Point();
            //蛇前进,实现原理就是头加尾减,若吃到食物,头加尾不减
            switch(direction) {
                case UP:
                    newhead.x = orighead.x;
                    newhead.y = orighead.y  - BOXWIDTH ;
                    break;
                case DOWN:
                    newhead.x = orighead.x;
                    newhead.y = orighead.y  + BOXWIDTH ;
                    break;
                case LEFT:
                    newhead.x = orighead.x  - BOXWIDTH;
                    newhead.y = orighead.y;
                    break;
                case RIGHT:
                    newhead.x = orighead.x + BOXWIDTH ;
                    newhead.y = orighead.y;
                    break;
                default:
                    break;
            }
            adjustHead(newhead);
            list.add(0, newhead);
        }
    
        //边界判断
        private boolean isOutBound(Point point) {
            if(point.x < sXOffset || point.x > mWidth - sXOffset) return true;
            if(point.y < sYOffset || point.y > mHeight - sYOffset) return true;
            return false;
        }
    
        //出了边界,重新回来
        private void adjustHead(Point point) {
            //Log.e(TAG, "checkBound = " + isOutBound(point));
            if(isOutBound(point)){
                if(mSnakeDirection == UP) point.y = mHeight - sYOffset - BOXWIDTH;
                if(mSnakeDirection == DOWN) point.y = sYOffset;
                if(mSnakeDirection == LEFT) point.x = mWidth - sYOffset - BOXWIDTH;
                if(mSnakeDirection == RIGHT) point.x = sXOffset;
            }
        }
    
        //判断食物是否可以被吃
        private boolean isFoodEaten() {
            if(!mIsFoodDone) {
                Rect foodrect = new Rect(mFoodPosition.x, mFoodPosition.y, mFoodPosition.x + BOXWIDTH, mFoodPosition.y + BOXWIDTH);
                Point head = mSnakeList.get(0);
                Rect headrect = new Rect(head.x, head.y, head.x + BOXWIDTH , head.y + BOXWIDTH);
                return foodrect.intersect(headrect);
            }
            return false;
        }
    
    }

    效果展示:
    (制作Gif有点不流畅实际效果很流畅)

    这里写图片描述

    代码附件:
    http://download.csdn.net/detail/poorkick/9497370

    欢迎讨论!

  • 相关阅读:
    AngularJs 键盘事件和鼠标事件
    Linux的net.ipv4.tcp_timestamps参数
    实战:tcp链接rst场景tcpdump分析
    C++ map使用总结
    C++ 11常见功能介绍:auto,decltype,nullptr,for,lambda
    BLOCK层基本概念:bio,request,request_queue
    C: 字符数组中的空去掉
    代码静态分析工具-splint的学习与使用[转]
    代码分析工具splint安装介绍
    gcc/g++ 如何支持c11/c++11标准编译
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6467214.html
Copyright © 2011-2022 走看看