android 简单的贪吃蛇小游戏

贪吃蛇是一款经典的小游戏,游戏比较简单,实现也比较简单。

本篇博客将详细介绍我自己写的贪吃蛇的思路以及实现方式。

首先我们需要在游戏界面将游戏区域划分成无数个小方格,类似下图

画布(游戏区域)的宽为 width 高为 height ,列数 sizex=width/pointSize ,行数 sizey=height/pointSize. 由于画布的长宽不一定是pointSize的整数倍,所以为了所有的数据居中需要设置 x轴 y轴的偏移量(当前貌似偏移量可有可无,本人强迫症一定要加上),offsetX=(width - sizex*pointSize)/ 2,offsetY=(height - sizey*pointSize) / 2.

新建数组 spoints=new int[ sizex ][ sizey ] 用于保存方格矩阵 其中 spoints[x][y]==1说明该点属于当前小蛇身体的一部分, spoints[x][y]==0则表示小蛇当前未运动到此点。

新建 ArrayList<Point> points=new ArrayList<Point>(); 用于保存小蛇的身体的所有节点(points 中的 所有point的x,y对应的是 spoints数组的所有值为1的点的下标),points.get(0) 为头部坐标点,最后一个为尾部坐标点

   

 上面两幅图片代表的意思相同,都表示小蛇的当前状态(小蛇画的比较丑,请见谅)

下面开始考虑的小蛇的移动,小蛇的移动可以看成是将小蛇的尾巴的移动到小蛇的头部(根据方向判断移动的上下左右位置),其他的节点保持不动,见图示

得到下图运动后的状态

然后修改spoints数组对应的坐标的值,新增的头部对应的值修改为 1,移除的尾部的值修改为 0. 并将对应的坐标点加入points链表的对应位置,移除尾部的坐标点

解决了小蛇的移动问题,再来解决小蛇吃食物点的问题。

当小蛇吃到食物的时候,相当于将食物的点当成新的头部,而尾部不变,这样就相当于吃了之后变长了

这样就完成了小蛇的增长。

没有代码那就是耍流氓!!下面开始贴代码

git代码下载: 贪吃蛇          https://gitee.com/wuchang0213/TCS.git

csdn下载:https://download.csdn.net/download/weixin_41191134/10832869

再提供一个数独小游戏的下载:https://download.csdn.net/download/weixin_41191134/10832903

只贴了要的游戏界面的代码

public class TcsView extends View {

    private Paint paint;
    //小蛇的组成点
    private ArrayList<Point> points=new ArrayList<Point>();
    private Point pointFood=new Point();//食物点
    //游戏界面的 方格划分
    private int[][] spoints;
    //方格数组的大小
    private int sizex;
    private int sizey;
    //小蛇的头部对应在数组中的位置
    private int headerX;
    private int headerY;
    //食物的坐标点
    private int foodX;
    private int foodY;
    //偏移量
    private int offsetX=0;
    private int offsetY=0;
    //随机数
    private Random random=new Random();
    private boolean isStart=true;
    //屏幕宽高
    private int width;
    private int height;
    //小蛇方块的大小
    private int pointSize=20;
    //方向
    private int direction=0;// 0 上 -1 下  1 左 2 右
    //触摸点坐标
    private float tdx;
    private float tdy;
    private boolean isStop=false;
    private TcsScoreListener tcsScoreListener;

    private Handler handler=new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message message) {
            switch (message.what){
                case 1:
                    headerNext();
                    break;
            }
            return false;
        }
    });

    private void headerNext(){
        if(points.size()==0||isStop||foodX==-1) return;
        //小蛇的移动控制,可以看成是小蛇的首尾发生了移动,
        // 头部根据下一次移动的方向移动到下一格,然后去掉结尾
        switch (direction){
            case 0:
                headerY--;
                break;
            case -1:
                headerY++;
                break;
            case 1:
                headerX--;
                break;
            case 2:
                headerX++;
                break;
        }
        //判断是否到达边界
        if(headerX<0||headerY<0){
            isStop=true;
        }else {
            //判断小蛇是否吃到自己
            if(spoints[headerX][headerY]==1){
                isStop=true;
            }
            points.add(0,new Point(headerX,headerY));
            spoints[headerX][headerY]=1;
            if(tcsScoreListener!=null){
                tcsScoreListener.onTCSScore(points.size());
            }
            if(headerX==foodX && headerY==foodY){
                foodX=-1;
                foodY=-1;
                initPointFood();
            }else {
                Point move=points.get(points.size()-1);
                spoints[move.x][move.y]=0;
                points.remove(points.size() - 1);
            }
            if (!isStop){
                invalidate();
            }
        }
    }

    public TcsView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint=new Paint();
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(1);
        paint.setAntiAlias(true);
        //100为时间的发生间隔,即小蛇多久移动一次,此处修改可调节小蛇的速度
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                handler.sendEmptyMessage(1);
            }
        },0,100);
    }

    public void setTcsScoreListener(TcsScoreListener tcsScoreListener) {
        this.tcsScoreListener = tcsScoreListener;
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        width=getWidth();
        height=getHeight();

        if(isStart){
            //根据宽高以及 pointSize 将游戏区域划分成不同的矩形区块,
            sizex=width/pointSize;
            sizey=height/pointSize;
            spoints=new int[sizex][sizey];
            //计算偏移量
            offsetX=(width-(sizex*pointSize))/2;
            offsetY=(height-(sizey*pointSize))/2;
            //头部起始坐标默认在屏幕中央
            headerX=sizex/2;
            headerY=sizey/2;
            spoints[headerX][headerY]=1;
            points.add(0,new Point(headerX,headerY));
            initPointFood();
            isStart=false;
        }
        for(int i=0;i<points.size();i++){
            Point point=points.get(i);
            drawPoint(canvas,paint,point);
        }
        drawPoint(canvas,paint,pointFood);
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(!isStop) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    tdx = event.getX();
                    tdy = event.getY();
                    break;
                case MotionEvent.ACTION_UP:
                    float dx = Math.abs(tdx - event.getX());
                    float dy = Math.abs(tdy - event.getY());
                    if (dx > 40 || dy > 40) {
                        //判断为滑动,不是点击
                        Log.d("*****onTouchEvent****", "/**/*/*//*////*98*8/*9*/89*898565/*** ");
                    } else {
                        if (direction == 0 || direction == -1) {
                            if (tdx > points.get(0).x) {
                                direction = 2;
                            } else {
                                direction = 1;
                            }
                        } else if (direction == 1 || direction == 2) {
                            if (tdy > points.get(0).y) {
                                direction = -1;
                            } else {
                                direction = 0;
                            }
                        }
                        handler.sendEmptyMessage(1);
                    }
                    break;
            }
        }
        return super.onTouchEvent(event);
    }

    //根据点的左边画出对应的点
    private void drawPoint(Canvas canvas,Paint paint,Point point){
        RectF rectF=new RectF(
                offsetX+point.x*pointSize,
                offsetY+point.y*pointSize,
                offsetX+(point.x+1)*pointSize,
                offsetY+(point.y+1)*pointSize);
        canvas.drawRect(rectF,paint);
    }

    /**
     * 确定食物点的位置
     */
    private void initPointFood(){
        foodX=random.nextInt(sizex);//获取随机的坐标点
        foodY=random.nextInt(sizey);
        //判断当前坐标点是否在小蛇的轨迹上
        if(spoints[foodX][foodY]==1){
            initPointFood();
        }else {
            //标准化坐标位置
            pointFood.set(foodX,foodY);
        }
    }

    /**
     * 根据传入的参数 修改小蛇的运动方向
     * @param dire
     */
    public void changeDirection(int dire) {
        switch (dire){
            case 0:// 小蛇上下运动时 可修改为左右运动
            case -1:
                if(direction==1||direction==2){
                    direction=dire;
                }
                break;
            case 1://小蛇左右运动时 可修改方向为上下运动
            case 2:
                if(direction==0||direction==-1){
                    direction=dire;
                }
                break;
        }
    }

    /**
     * 设置重新开始
     */
    public void restart(){
        isStop=false;
        isStart=true;
        points.clear();
        invalidate();
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_41191134/article/details/84855621