1. 程式人生 > >android 簡單的貪吃蛇小遊戲

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();
    }
}