贪吃蛇android源码分享

本文分享了作者亲自动手制作贪吃蛇Android游戏的过程,详细介绍了游戏的关键代码,包括Point类用于记录蛇的位置,Snake类负责绘制蛇和食物,以及MySnakeView类作为游戏逻辑的核心。游戏逻辑涉及蛇身位置的生成与判断、移动机制以及碰撞检测。文章还提供了部分代码示例和游戏运行界面截图,并给出了更多源码分享链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

闲来无事就想写个游戏来耍耍。想来想去,就计划写个贪吃蛇。开始的时候不知道怎么下手,自己也不想上网用别人的代码,后来不断地翻书。终于让我找到了一个好方法,那就是自己绘画贪吃蛇和食物。
下面就是我具体代码的分析。

主要代码有分布在三个类中:
1、Point类:记录蛇身位置(左上角和右下角坐标)。
2、Snake类:负责画蛇身和食物。
3、MySnakeView类:继承于View,并且处理逻辑。

主要思维:
1、游戏蛇身和食物位置的产生和判断:首先初始化的的蛇身方块放到另一个一个list表snake中,然后将屏幕上蛇身能够经过的方块位置放在一个表中(去除蛇身自方块,也就是snake表中的蛇身方块),以便于在不是蛇身位置产生食物。

2、蛇身的移动:在新线程中设置移动速度,不断地在画布上画相关内容,移动逻辑是上一个蛇身方块不断替换下一个蛇身方块,从而达到移动效果。

3、碰撞检测:检测是否触碰到屏幕边缘,和吃到自己。

好了,下面就是代码了。

一、Point类:

package com.example.mysnakegame;


public class Point {//方块左上角坐标,右下角坐标

    private float snakeX,snakeY,snakeBottomX,snakeBottomY;

    public Point(float snakeX,float snakeY,float snakeBottomX,float snakeBottomY,
            boolean isSnake,boolean isFood){
        this.snakeX = snakeX;//左上角X
        this.snakeY = snakeY;//左上角Y
        this.snakeBottomX = snakeBottomX;//右下角X
        this.snakeBottomY = snakeBottomY;//右下角Y
    }

    public float getSnakeX() {
        return snakeX;
    }

    public float getSnakeY() {
        return snakeY;
    }

    public float getSnakeBottomX() {
        return snakeBottomX;
    }

    public float getSnakeBottomY() {
        return snakeBottomY;
    }

    public boolean isEqualSnake(Snake snake){//判断两个方块是否相同
        boolean flag = false;
        if (Math.abs(snake.getSnakeX()-this.snakeX)<1e-4&&
                Math.abs(snake.getSnakeY()-this.snakeY)<1e-4&&
                Math.abs(snake.getSnakeBottomX()-this.snakeBottomX)<1e-4&&
                Math.abs(snake.getSnakeBottomY()-this.snakeBottomY)<1e-4
                ) {
            flag = true;
        }
        return flag;
    }

}

二、Snake类:

package com.example.mysnakegame;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

public class Snake {//画蛇身方块
    float snakeX,snakeY,snakeBottomX,snakeBottomY,moveDistance;//蛇身方块的左上角坐标
    private Paint paint;
    private boolean isHead;

    public Snake(){
        snakeX = 0;
        snakeY = 0;
        snakeBottomX = 0;
        snakeBottomY = 0;
        moveDistance = 0;
        isHead = false;
        paint = new Paint();
        paint.setColor(Color.GRAY);
    }

    public void setParameter(float snakeX,float snakeY,float snakeBottomX,
            float snakeBottomY,float moveDistance){//设置蛇身方块的位置参数
        this.snakeX = snakeX;
        this.snakeY = snakeY;
        this.snakeBottomX = snakeBottomX;
        this.snakeBottomY = snakeBottomY;
        this.moveDistance = moveDistance;

    }

    public void setHead(boolean b){//设置蛇头
        isHead = b;
    }

    public boolean isSnakeHead(){//判断蛇头
        return isHead;
    }

    public void setHeadPaintColor(int color){//设置画笔的颜色
        paint.setColor(color);
    }
    public void draw(Canvas canvas){
        canvas.drawRect(snakeX+1, snakeY+1, snakeBottomX-1, snakeBottomY-1, paint);
    }

    public float getSnakeX(){
        return this.snakeX;
    }

    public float getSnakeY(){
        return this.snakeY;
    }

    public float getSnakeBottomX(){
        return this.snakeBottomX;
    }

    public float getSnakeBottomY(){
        return this.snakeBottomY;
    }

    public void addSnakeX(){
        snakeX+=moveDistance;
    }

    public void addSnakeY(){
        snakeY+=moveDistance;
    }

    public void addSnakeBottomX(){
        snakeBottomX+=moveDistance;
    }

    public void addSnakeBottomY(){
        snakeBottomY+=moveDistance;
    }

    public void reduceSnakeX(){
        snakeX-=moveDistance;
    }

    public void reduceSnakeY(){
        snakeY-=moveDistance;
    }

    public void reduceSnakeBottomX(){
        snakeBottomX-=moveDistance;
    }

    public void reduceSnakeBottomY(){
        snakeBottomY-=moveDistance;
    }

    public boolean isEqualSnake(Snake snake){
        boolean flag = false;
        if (Math.abs(snake.getSnakeX()-this.snakeX)<1e-4&&
                Math.abs(snake.getSnakeY()-this.snakeY)<1e-4&&
                Math.abs(snake.getSnakeBottomX()-this.snakeBottomX)<1e-4&&
                Math.abs(snake.getSnakeBottomY()-this.snakeBottomY)<1e-4
                ) {
            flag = true;
        }
        return flag;
    }
}

三、MySnakeView类:

package com.example.mysnakegame;

import java.util.ArrayList;
import java.util.List;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;

public class MySnakeView extends View implements Runnable{

    private float snakeX,snakeY;//贪吃蛇方块位置
    private float snakeBottomX,snakeBottomY;//贪吃蛇方块右下标位置
    private float moveDistance;//每次移动的距离
    private float screenWidth;
    private final int LEFT = 1;//向左运动
    private final int RIGHT = 2;//向右运动
    private final int UP = 3;//向上运动
    private final int DOWN = 4;//向下运动
    private int state;//蛇头的状态
    private List<Snake> snake;//存放蛇身方块
    private Paint paint;//蛇身活动区域画笔
    private List<Point> snakeAddFoodArea;//食物产生区域
    private Point food;//食物

    public MySnakeView(Context context) {
        super(context);
        init();
    }

    public MySnakeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public MySnakeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }


    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        paint = new Paint();
        paint.setColor(Color.WHITE);
        canvas.drawRect(0, 0, screenWidth, screenWidth, paint);
        drawFood(canvas);//画食物
        for (int i = 0; i < snake.size(); i++) {
            Snake s = snake.get(i);
            s.draw(canvas);
        }
        super.onDraw(canvas);
    }

    @SuppressWarnings("deprecation")
    private void init(){//初始化View
        WindowManager wm = (WindowManager) getContext()
                .getSystemService(Context.WINDOW_SERVICE);
        screenWidth = wm.getDefaultDisplay().getWidth();
        setMeasuredDimension((int)screenWidth, (int)screenWidth);
        moveDistance = screenWidth/10;//获取每次移动的距离
        snake = new ArrayList<Snake>();//储存蛇身方块
        snakeAddFoodArea = new ArrayList<Point>();//储存未被蛇身占有的方块以供产生食物
        snakeX = 0;
        snakeY = 0;
        snakeBottomX = moveDistance;
        snakeBottomY = moveDistance;
        initSnakeGame();
        Thread thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() {//新线程不断刷屏
        while(true){
            try {
                Thread.sleep(500);//设置移动速度
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            moveSnake();
        }
    }

    private void initSnakeGame(){//初始化蛇身
        state = RIGHT;
        if(!snake.isEmpty()){
            snake.removeAll(snake);
        }
        int i;
        for (i = 0; i < 3; i++) {
            Snake body = new Snake();
            body.setParameter(snakeX+moveDistance*i, snakeY, snakeBottomX+moveDistance*i,snakeBottomY,moveDistance);
            if(i == 2){ 
                body.setHeadPaintColor(Color.DKGRAY);
                body.setHead(true);
            } 
            snake.add(body);
        }
        addFood();
    }

    private void addFood(){//添加食物
        initFoodArea();
        System.out.println("snake.size   "+snake.size());
        for(int i = 0 ; i < snake.size(); i++){
            for(int j = 0 ; j < snakeAddFoodArea.size(); j++){
                if(snakeAddFoodArea.get(j).isEqualSnake(snake.get(i))){
                    snakeAddFoodArea.remove(j);
                    System.out.println("移除移除");
                    break;
                }
            }
        }

        food = snakeAddFoodArea.get((int)(Math.random()*(snakeAddFoodArea.size())));

    }

    private boolean isEatenFood(){//判断蛇头是否吃了食物
        return food.isEqualSnake(snake.get(snake.size()-1));
    }
    private void drawFood(Canvas canvas){//画食物
        Paint paintFood = new Paint();
        paintFood.setColor(Color.GREEN);
        canvas.drawRect(food.getSnakeX(), food.getSnakeY(), 
                food.getSnakeBottomX(), food.getSnakeBottomY(), paintFood);
    }
    private void initFoodArea(){//初始化食物产生区域
        if(snakeAddFoodArea.size()>1){
            snakeAddFoodArea.removeAll(snakeAddFoodArea);
        }
        for(int j = 0; j < 10; j++){//存入所有蛇身活动区域的点
            for(int i = 0 ; i < 10; i++){
                snakeAddFoodArea.add(new Point(snakeX+moveDistance*i, 
                        snakeY+moveDistance*j,
                        snakeBottomX+moveDistance*i,
                        snakeBottomY+moveDistance*j, 
                        false, false));
            }
        }
    }

    private void moveSnake(){//移动蛇身,PS:上一个蛇身不断替换上一个蛇身的位置,达到蛇移动的效果
        postInvalidate();
        Snake headSnake = headPosition();
        if (headSnake!=null) {
            snake.get(snake.size()-1).setHeadPaintColor(Color.GRAY);
            snake.add(headSnake);
            snake.get(snake.size()-1).setHeadPaintColor(Color.DKGRAY);
        }

        if (!isEatenFood()) {
            snake.remove(0);

        }else{
            addFood();
        }

            if(checkGameOver()){
                    initSnakeGame();
            }
    }

    private Snake  headPosition() {//设置蛇头的位置
        Snake head = new Snake();
        head.setParameter(snake.get(snake.size()-1).getSnakeX(),
                snake.get(snake.size()-1).getSnakeY(), 
                snake.get(snake.size()-1).getSnakeBottomX(), 
                snake.get(snake.size()-1).getSnakeBottomY(), moveDistance);

        switch (state) {
        case LEFT:
            head.reduceSnakeX();
            head.reduceSnakeBottomX();
            break;

        case RIGHT:
            head.addSnakeX();
            head.addSnakeBottomX();
            break;

        case UP:
            head.reduceSnakeY();
            head.reduceSnakeBottomY();
            break;

        case DOWN:
            head.addSnakeY();
            head.addSnakeBottomY();
            break;
        default:
            return null;
        }
        System.err.println("snakeX"+snake.get(snake.size()-1).getSnakeX()
                +",snakeY"+snake.get(snake.size()-1).getSnakeX()
                +",snakeBottomX"+snake.get(snake.size()-1).getSnakeBottomX()+
                ",snakeBottomY"+snake.get(snake.size()-1).getSnakeBottomX()+"\n\n");
        return head;
    }

    private boolean checkGameOver(){//检验游戏是否结束
        boolean flag = false;
        if(isEatSelf()||isKnockWall()){
            flag = true;
        }
        return flag;
    }

    private boolean isEatSelf(){//吃到自己
        boolean flag = false;
        Snake head = snake.get(snake.size()-1);
        for(int i = 0; i < snake.size()-1; i++){
            if(head.isEqualSnake(snake.get(i))){
                flag = true;
                break;
            }
        }
        return flag;
    }

    private boolean isKnockWall(){//边缘碰撞检测
        boolean flag = false;
        Snake head = snake.get(snake.size()-1);

        switch (state) {
        case LEFT:
            if(head.getSnakeX() < 0){
                flag = true;
            }
            break;

        case RIGHT:
            if(head.getSnakeBottomX() > screenWidth){
                flag = true;
            }
            break;

        case DOWN:
            if(head.getSnakeBottomY() > screenWidth){
                flag = true;
            }
            break;

        case UP:
            if(head.getSnakeY() < 0){
                flag = true;
            }
            break;
        default:
            break;
        }
        return flag;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {//移动状态获取
        Snake s = snake.get(snake.size()-1);
        float x,y;
        x = event.getX();
        y = event.getY();

        switch (state) {
        case LEFT:
            if(s.getSnakeY() > y){
                state = UP;
            }
            if(s.getSnakeBottomY() < y){
                state = DOWN;
            }
            break;

        case RIGHT:
            if(s.getSnakeY() > y){
                state = UP;
            }
            if(s.getSnakeBottomY() < y){
                state = DOWN;
            }
            break;

        case UP:
            if(s.getSnakeX() > x){
                state = LEFT;
            }

            if(s.getSnakeBottomX() < x){
                state = RIGHT;
            }
            break;

        case DOWN:
            if(s.getSnakeX() > x){
                state = LEFT;
            }

            if(s.getSnakeBottomX() < x){
                state = RIGHT;
            }
            break;
        default:
            break;
        }

        return super.onTouchEvent(event);
    }

}

好了,主要逻辑代码就这些,运行界面如下:

这里写图片描述







更多博主源码分享:
2048增强版(可以自己设置方块数,还方块上面出现的数字,方块出现的几率)

模仿QQ侧滑菜单实现生日快乐祝福软件

贪吃蛇源码分享地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值