• java小游戏-贪吃蛇


    连接视频


    1 窗口创建

    创建GameWin 主类

    package snake;
    
    import javax.swing.*;
    
    public class GameWin extends JFrame {
    
        public void launch() {
            //设置窗口是否可见
            setVisible(true);
            //设置窗口大小
            setSize(600, 600);
            //设置窗口的位置在屏幕上居中
            setLocationRelativeTo(null);
            //设置窗口的标题
            this.setTitle("贪吃蛇");
        }
    
        public static void main(String[] args) {
            GameWin gameWin = new GameWin();
            gameWin.launch();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    运行效果:

    在这里插入图片描述

    2 网格绘制

    在GameWin类重写paint方法

    @Override
    public void paint(Graphics g) {
        //灰色背景
        g.setColor(Color.gray);
        //填充矩形
        g.fillRect(0, 0, 600, 600);
        //绘制网格线颜色
        g.setColor(Color.BLACK);
        //批量绘制网格线
        for (int i = 0; i < 20; i++) {
            //横线
            g.drawLine(0, i * 30, 600, i * 30);
            //竖线
            g.drawLine(i * 30, 0, i * 30, 600);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    运行效果:

    在这里插入图片描述

    3 游戏物体父类编写

    创建GameObj类

    package snake;
    
    import java.awt.*;
    
    public class GameObj {
        //图片
        Image image;
        //坐标
        int x;
        int y;
        //宽高
        int width = 30;
        int height = 30;
        //窗口类的引用
        GameWin gameWin;
    
        public Image getImage() {
            return image;
        }
    
        public void setImage(Image image) {
            this.image = image;
        }
    
        public int getX() {
            return x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    
        public int getWidth() {
            return width;
        }
    
        public void setWidth(int width) {
            this.width = width;
        }
    
        public int getHeight() {
            return height;
        }
    
        public void setHeight(int height) {
            this.height = height;
        }
    
        public GameWin getGameWin() {
            return gameWin;
        }
    
        public void setGameWin(GameWin gameWin) {
            this.gameWin = gameWin;
        }
    
        public GameObj() {
        }
    
        public GameObj(Image image, int x, int y, int width, int height, GameWin gameWin) {
            this.image = image;
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            this.gameWin = gameWin;
        }
        
        public GameObj(Image image, int x, int y, GameWin gameWin) {
            this.image = image;
            this.x = x;
            this.y = y;
            this.gameWin = gameWin;
        }
    
        //绘制自身
        public void printSelf(Graphics g) {
            //读取图片
            g.drawImage(image, x, y, null);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    4 游戏工具类的创建

    创建GameUtils类,在当前项目下创建snakeimg文件夹,放入图片

    package snake;
    
    import java.awt.*;
    
    public class GameUtils {
        //蛇头【四张图片】
        public static Image upImg = Toolkit.getDefaultToolkit().getImage("snakeimg/up.png");
        public static Image downImg = Toolkit.getDefaultToolkit().getImage("snakeimg/down.png");
        public static Image leftImg = Toolkit.getDefaultToolkit().getImage("snakeimg/left.png");
        public static Image rightImg = Toolkit.getDefaultToolkit().getImage("snakeimg/right.png");
        //蛇身
        public static Image bodyImg = Toolkit.getDefaultToolkit().getImage("snakeimg/body.png");
        //食物
        public static Image foodImg = Toolkit.getDefaultToolkit().getImage("snakeimg/food.png");
    
        /**
         * 绘制文字
         *
         * @param g
         * @param str   文字
         * @param color 颜色
         * @param size  文字大小
         * @param x     x坐标
         * @param y     y坐标
         */
        public static void drawWord(Graphics g, String str, Color color, int size, int x, int y) {
            g.setColor(color);
            g.setFont(new Font("仿宋", Font.BOLD, size));
            g.drawString(str, x, y);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    5 蛇头部的绘制

    创建HeadObj类型

    package snake;
    
    import java.awt.*;
    
    public class HeadObj extends GameObj{
        //方向 up down left right
        private String direction= "right";
    
        public String getDirection() {
            return direction;
        }
    
        public void setDirection(String direction) {
            this.direction = direction;
        }
    
        public HeadObj(Image image, int x, int y, GameWin gameWin) {
            super(image, x, y, gameWin);
        }
    
        @Override
        public void printSelf(Graphics g) {
            super.printSelf(g);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在GameWin类引用HeadObj对象

    public class GameWin extends JFrame {
    
        //蛇头对象
        HeadObj headObj = new HeadObj(GameUtils.rightImg,30,570,this);
    
        ....
    
        @Override
        public void paint(Graphics g) {
            //灰色背景
            g.setColor(Color.gray);
            //填充矩形
            g.fillRect(0, 0, 600, 600);
            //绘制网格线颜色
            g.setColor(Color.BLACK);
            //批量绘制网格线
            for (int i = 0; i < 20; i++) {
                //横线
                g.drawLine(0, i * 30, 600, i * 30);
                //竖线
                g.drawLine(i * 30, 0, i * 30, 600);
            }
            //绘制蛇头
            headObj.printSelf(g);
        }
    
    	....
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    运行效果:

    在这里插入图片描述

    6 蛇头的简单移动

    在HeadObj类添加move方法

    @Override
    public void printSelf(Graphics g) {
        super.printSelf(g);
        move();
    }
    
    //蛇的移动
    public void move() {
        switch (direction) {
            case "up":
                y -= height;
                break;
            case "down":
                y += height;
                break;
            case "left":
                x -= width;
                break;
            case "right":
                x += width;
                break;
            default:
                break;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在GameWin类launch方法添加循环绘制

    public void launch() {
        //设置窗口是否可见
        setVisible(true);
        //设置窗口大小
        setSize(600, 600);
        //设置窗口的位置在屏幕上居中
        setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");
        while (true){
            repaint();
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    7 键盘控制蛇的方向

    在HeadObj类构造器中添加键盘监听事件,和changeDirection方法

    public HeadObj(Image image, int x, int y, GameWin gameWin) {
        super(image, x, y, gameWin);
        //键盘监听事件
        this.gameWin.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                changeDirection(e);
            }
        });
    }
    
    //控制移动方向 W-up S-down A-left D-right
    public void changeDirection(KeyEvent e){
       switch (e.getKeyCode()){
           case KeyEvent.VK_A:
               if(!"right".equals(direction)){
                   direction = "left";
                   image = GameUtils.leftImg;
               }
               break;
           case KeyEvent.VK_D:
               if(!"left".equals(direction)){
                   direction = "right";
                   image = GameUtils.rightImg;
               }
               break;
           case KeyEvent.VK_W:
               if(!"down".equals(direction)){
                   direction = "up";
                   image = GameUtils.upImg;
               }
               break;
           case KeyEvent.VK_S:
               if(!"up".equals(direction)){
                   direction = "down";
                   image = GameUtils.downImg;
               }
               break;
           default:
               break;
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    8 蛇的越界处理

    在HeadObj类printSelf方法添加越界处理

    @Override
    public void printSelf(Graphics g) {
        super.printSelf(g);
        move();
        //越界处理
        if (x < 0) {
            x = 570;
        } else if (x > 570) {
            x = 0;
        }else if (y < 30) {//考虑游戏框框
            y = 570;
        }else if (y > 570) {
            y = 30;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    9 蛇身的添加和移动

    创建BodyObj类

    public class BodyObj extends GameObj{
    
        public BodyObj(Image image, int x, int y, GameWin gameWin) {
            super(image, x, y, gameWin);
        }
    
        @Override
        public void printSelf(Graphics g) {
            super.printSelf(g);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在GameWin类添加BodyObj 对象和 绘制

    public class GameWin extends JFrame {
    
        //蛇头对象
        HeadObj headObj = new HeadObj(GameUtils.rightImg,30,570,this);
        //蛇身的集合
        public List<BodyObj> bodyObjList = new ArrayList<>();
    
        public void launch() {
            //设置窗口是否可见
            setVisible(true);
            //设置窗口大小
            setSize(600, 600);
            //设置窗口的位置在屏幕上居中
            setLocationRelativeTo(null);
            //设置窗口的标题
            this.setTitle("贪吃蛇");
    
            //蛇身的初始化
            bodyObjList.add(new BodyObj(GameUtils.bodyImg,30,570,this));
            bodyObjList.add(new BodyObj(GameUtils.bodyImg,0,570,this));
    
            while (true){
                repaint();
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        @Override
        public void paint(Graphics g) {
            //灰色背景
            g.setColor(Color.gray);
            //填充矩形
            g.fillRect(0, 0, 600, 600);
            //绘制网格线颜色
            g.setColor(Color.BLACK);
            //批量绘制网格线
            for (int i = 0; i < 20; i++) {
                //横线
                g.drawLine(0, i * 30, 600, i * 30);
                //竖线
                g.drawLine(i * 30, 0, i * 30, 600);
            }
            //绘制蛇身[在蛇头前] 反向遍历 防止身体重叠
            for (int i = bodyObjList.size() - 1; i >= 0; i--) {
                bodyObjList.get(i).printSelf(g);
            }
            //绘制蛇头
            headObj.printSelf(g);
        }
    
        ....
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    在HeadObj类move方法添加蛇身移动

    //蛇的移动
    public void move() {
        //蛇身移动
        List<BodyObj> bodyObjList = this.gameWin.bodyObjList;
        for (int i = 1; i < bodyObjList.size(); i++) {
            bodyObjList.get(i).x = bodyObjList.get(i - 1).x;
            bodyObjList.get(i).y = bodyObjList.get(i - 1).y;
        }
    
        bodyObjList.get(0).x = this.x;
        bodyObjList.get(0).y = this.y;
    
        //蛇头移动
        switch (direction) {
            case "up":
                y -= height;
                break;
            case "down":
                y += height;
                break;
            case "left":
                x -= width;
                break;
            case "right":
                x += width;
                break;
            default:
                break;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    10 食物的随机位置生成

    创建FoodObj类

    public class FoodObj extends GameObj {
    
        //随机函数
        Random random = new Random();
    
        public FoodObj() {
        }
    
        public FoodObj(Image image, int x, int y, GameWin gameWin) {
            super(image, x, y, gameWin);
        }
    
        //获取食物 x=30-570 y=0-570
        public FoodObj getFood() {
            return new FoodObj(GameUtils.foodImg, random.nextInt(20) * 30,
                    (random.nextInt(19) + 1) * 30, this.gameWin);
        }
    
        @Override
        public void printSelf(Graphics g) {
            super.printSelf(g);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在GameWin类添加FoodObj 对象

    public class GameWin extends JFrame {
    
        //蛇头对象
        HeadObj headObj = new HeadObj(GameUtils.rightImg,30,570,this);
        //蛇身的集合
        public List<BodyObj> bodyObjList = new ArrayList<>();
        //获取食物对象
        public FoodObj food = new FoodObj().getFood();
    
      	....
    
        @Override
        public void paint(Graphics g) {
            //灰色背景
            g.setColor(Color.gray);
            //填充矩形
            g.fillRect(0, 0, 600, 600);
            //绘制网格线颜色
            g.setColor(Color.BLACK);
            //批量绘制网格线
            for (int i = 0; i < 20; i++) {
                //横线
                g.drawLine(0, i * 30, 600, i * 30);
                //竖线
                g.drawLine(i * 30, 0, i * 30, 600);
            }
            //绘制蛇身[在蛇头前] 反向遍历 防止身体重叠
            for (int i = bodyObjList.size() - 1; i >= 0; i--) {
                bodyObjList.get(i).printSelf(g);
            }
            //绘制蛇头
            headObj.printSelf(g);
            //绘制食物
            food.printSelf(g);
        }
    
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    11 蛇吃食物和食物重新生成

    在HeadObj类printSelf方法添加吃食物代码

    @Override
    public void printSelf(Graphics g) {
    	super.printSelf(g);
    	//蛇吃食物
    	FoodObj food = this.gameWin.food;
    	if (this.x == food.x && this.y == food.y) {
    		this.gameWin.food = food.getFood();
    	}
    	
    	move();
    	//越界处理
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    12 蛇的增长

    在HeadObj类中修改printSelf方法和move方法

    @Override
    public void printSelf(Graphics g) {
        super.printSelf(g);
        //蛇吃食物
        Integer newX = null;
        Integer newY = null;
        FoodObj food = this.gameWin.food;
        if (this.x == food.x && this.y == food.y) {
            this.gameWin.food = food.getFood();
            BodyObj lastBody =
                    this.gameWin.bodyObjList.get(this.gameWin.bodyObjList.size() - 1);
            newX = lastBody.x;
            newY = lastBody.y;
        }
    
        move();
    
        //move()结束后,新的bodyObj对象添加到bodyList中
        if (newX != null && newY != null) {
            this.gameWin.bodyObjList.add(new BodyObj(GameUtils.bodyImg, newX, newY, this.gameWin));
        }
    
        //越界处理
        ....
    }
    
    //蛇的移动
    public void move() {
        //蛇身移动 反向遍历
        List<BodyObj> bodyObjList = this.gameWin.bodyObjList;
        for (int i = bodyObjList.size() - 1; i >= 1; i--) {
            bodyObjList.get(i).x = bodyObjList.get(i - 1).x;
            bodyObjList.get(i).y = bodyObjList.get(i - 1).y;
        }
    
        bodyObjList.get(0).x = this.x;
        bodyObjList.get(0).y = this.y;
    
        //蛇头移动
        ....
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    13 计分面板的编写

    在GameWin类添加计分对象

    public class GameWin extends JFrame {
    
        //分数
        public static int score = 0;
        //窗口宽高
        int winWidth = 800;
        int winHeight = 600;
    
        //蛇头对象
        HeadObj headObj = new HeadObj(GameUtils.rightImg, 30, 570, this);
        //蛇身的集合
        public List<BodyObj> bodyObjList = new ArrayList<>();
        //获取食物对象
        public FoodObj food = new FoodObj().getFood();
    
        public void launch() {
            //设置窗口是否可见
            setVisible(true);
            //设置窗口大小
            setSize(winWidth, winHeight);
            //设置窗口的位置在屏幕上居中
            setLocationRelativeTo(null);
            //设置窗口的标题
            this.setTitle("贪吃蛇");
    
            //蛇身的初始化
            ...
        }
    
        @Override
        public void paint(Graphics g) {
            //灰色背景
            g.setColor(Color.gray);
            //填充矩形
            g.fillRect(0, 0, winWidth, winHeight);
            //绘制网格线颜色
            g.setColor(Color.BLACK);
            //批量绘制网格线
            for (int i = 0; i < 20; i++) {
                //横线
                g.drawLine(0, i * 30, 600, i * 30);
                //竖线
                g.drawLine(i * 30, 0, i * 30, 600);
            }
            //绘制蛇身[在蛇头前] 反向遍历 防止身体重叠
            for (int i = bodyObjList.size() - 1; i >= 0; i--) {
                bodyObjList.get(i).printSelf(g);
            }
            //绘制蛇头
            headObj.printSelf(g);
            //绘制食物
            food.printSelf(g);
            //分数绘制
            GameUtils.drawWord(g, score + " 分", Color.BLUE, 50, 650, 300);
        }
    
    	...
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    在HeadOb类的printSelf方法添加分数计算

    @Override
    public void printSelf(Graphics g) {
        super.printSelf(g);
        //蛇吃食物
        Integer newX = null;
        Integer newY = null;
        FoodObj food = this.gameWin.food;
        if (this.x == food.x && this.y == food.y) {
            this.gameWin.food = food.getFood();
            BodyObj lastBody =
                    this.gameWin.bodyObjList.get(this.gameWin.bodyObjList.size() - 1);
            newX = lastBody.x;
            newY = lastBody.y;
            //分数+1
            GameWin.score++;
        }
    
        move();
    
        ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    14 游戏开始的提示语

    在GameWin类添加游戏开始的提示语

    public class GameWin extends JFrame {
    
    
        //游戏状态 0:未开始 1:游戏中 2:暂停 3:失败 4:通过
        public static int state = 0;
    
       
        public void launch() {
           ...
    
            while (true) {
                if (state == 1) {
                    //游戏中才调用
                    repaint();
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        @Override
        public void paint(Graphics g) {
            ...
            //分数绘制
            GameUtils.drawWord(g, score + " 分", Color.BLUE, 50, 650, 300);
            //绘制提示语
            g.setColor(Color.gray);
            prompt(g);
        }
    
        //绘制提示语
        public void prompt(Graphics g) {
            //未开始
            if (state == 0) {
                g.fillRect(120, 240, 400, 70);
                GameUtils.drawWord(g, "按下空格键开始游戏", Color.YELLOW, 35, 150, 290);
            }
        }
    
        ...
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    15 游戏开始和暂停的键盘事件

    在GameWin类launch方法中添加暂停的键盘事件

    public class GameWin extends JFrame {
    
      	..
    
        public void launch() {
            //设置窗口是否可见
            setVisible(true);
            //设置窗口大小
            setSize(winWidth, winHeight);
            //设置窗口的位置在屏幕上居中
            setLocationRelativeTo(null);
            //设置窗口的标题
            this.setTitle("贪吃蛇");
    
            //蛇身的初始化
            bodyObjList.add(new BodyObj(GameUtils.bodyImg, 30, 570, this));
            bodyObjList.add(new BodyObj(GameUtils.bodyImg, 0, 570, this));
    
            //键盘事件
            this.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                        switch (state) {
                            case 0://未开始
                                state = 1;//游戏中
                                break;
                            case 1://游戏中
                                state = 2;//暂停
                                repaint();
                                break;
                            case 2://暂停
                                state = 1;//游戏中
                                break;
                            default:
                                break;
                        }
                    }
                }
            });
    
            while (true) {
                if (state == 1) {
                    //游戏中才调用
                    repaint();
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
    	...
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    16 游戏通关的判定

    在HeadObj类printSelf方法添加通关分数

    @Override
    public void printSelf(Graphics g) {
        super.printSelf(g);
        //蛇吃食物
        Integer newX = null;
        Integer newY = null;
        FoodObj food = this.gameWin.food;
        if (this.x == food.x && this.y == food.y) {
            this.gameWin.food = food.getFood();
            BodyObj lastBody =
                    this.gameWin.bodyObjList.get(this.gameWin.bodyObjList.size() - 1);
            newX = lastBody.x;
            newY = lastBody.y;
            //分数+1
            GameWin.score++;
        }
    
        //通过判断
        if (GameWin.score >= 15) {
            //通过
            GameWin.state = 4;
        }
    
        move();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在GameWin类prompt方法添加绘制通关语

    //绘制提示语
    public void prompt(Graphics g) {
        //未开始
        if (state == 0) {
            g.fillRect(120, 240, 400, 70);
            GameUtils.drawWord(g, "按下空格键开始游戏", Color.YELLOW, 35, 150, 290);
        }
        //通关
        if (state ==4) {
            g.fillRect(120, 240, 400, 70);
            GameUtils.drawWord(g, "达成条件,游戏通关", Color.green, 35, 150, 290);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    17 蛇头与蛇身的碰撞判断

    在HeadObj类move方法添加蛇头与蛇身的碰撞判断

    //蛇的移动
    public void move() {
       //蛇身移动 反向遍历
       List<BodyObj> bodyObjList = this.gameWin.bodyObjList;
       for (int i = bodyObjList.size() - 1; i >= 1; i--) {
           bodyObjList.get(i).x = bodyObjList.get(i - 1).x;
           bodyObjList.get(i).y = bodyObjList.get(i - 1).y;
           //蛇头与身体的碰撞判断
           if(this.x == bodyObjList.get(i).x && this.y == bodyObjList.get(i).y){
               //失败
               GameWin.state = 3;
           }
       }
    
       bodyObjList.get(0).x = this.x;
       bodyObjList.get(0).y = this.y;
    
       //蛇头移动
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在GameWin类prompt方法添加失败语绘制

    //蛇头对象
    HeadObj headObj = new HeadObj(GameUtils.rightImg, 60, 570, this);
    
    //绘制提示语
    public void prompt(Graphics g) {
        //未开始
        if (state == 0) {
            g.fillRect(120, 240, 400, 70);
            GameUtils.drawWord(g, "按下空格键开始游戏", Color.YELLOW, 35, 150, 290);
        }
        //暂停
        if (state == 2) {
            g.fillRect(120, 240, 400, 70);
            GameUtils.drawWord(g, "按下空格键继续游戏", Color.YELLOW, 35, 150, 290);
        }
        //游戏失败
        if (state == 3) {
            g.fillRect(120, 240, 400, 70);
            GameUtils.drawWord(g, "咬到自己,游戏失败", Color.red, 35, 150, 290);
        }
        //通关
        if (state ==4) {
            g.fillRect(120, 240, 400, 70);
            GameUtils.drawWord(g, "达成条件,游戏通关", Color.green, 35, 150, 290);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    18 双缓存解决画面闪动问题

    在GameWin类中添加双缓存图片

    public class GameWin extends JFrame {
    
        ...
        //游戏状态 0:未开始 1:游戏中 2:暂停 3:失败 4:通过
        public static int state = 0;
        //定义双缓存图片
        Image offScreenImage = null;
    
        ...
    
        @Override
        public void paint(Graphics g) {
            //初始化双缓存图片
            if (offScreenImage == null) {
                offScreenImage = this.createImage(winWidth, winHeight);
            }
            //获取图片对应的graphics对象
            Graphics gImage = offScreenImage.getGraphics();
    
            //灰色背景
            gImage.setColor(Color.gray);
            //填充矩形
            gImage.fillRect(0, 0, winWidth, winHeight);
            //绘制网格线颜色
            gImage.setColor(Color.BLACK);
            //批量绘制网格线
            for (int i = 0; i < 20; i++) {
                //横线
                gImage.drawLine(0, i * 30, 600, i * 30);
                //竖线
                gImage.drawLine(i * 30, 0, i * 30, 600);
            }
            //绘制蛇身[在蛇头前] 反向遍历 防止身体重叠
            for (int i = bodyObjList.size() - 1; i >= 0; i--) {
                bodyObjList.get(i).printSelf(gImage);
            }
            //绘制蛇头
            headObj.printSelf(gImage);
            //绘制食物
            food.printSelf(gImage);
            //分数绘制
            GameUtils.drawWord(gImage, score + " 分", Color.BLUE, 50, 650, 300);
            //绘制提示语
            gImage.setColor(Color.gray);
            prompt(gImage);
            //将双缓存图片绘制到窗口中
            g.drawImage(offScreenImage, 0, 0, null);
        }
    	...
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    19 游戏失败后重新开始

    在GameWin类中添加游戏重置方法

    public class GameWin extends JFrame {
    
        //分数
        public int score = 0;
        //窗口宽高
        int winWidth = 800;
        int winHeight = 600;
        //游戏状态 0:未开始 1:游戏中 2:暂停 3:失败 4:通过 5:失败后重启
        public static int state = 0;
       
    
        public void launch() {
            ...
    
            //键盘事件
            this.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                        switch (state) {
                            case 0://未开始
                                state = 1;//游戏中
                                break;
                            case 1://游戏中
                                state = 2;//暂停
                                repaint();
                                break;
                            case 2://暂停
                                state = 1;//游戏中
                                break;
                            case 3://游戏失败
                                state = 5;//失败后重新开始
                                break;
                            default:
                                break;
                        }
                    }
                }
            });
    
            while (true) {
                if (state == 1) {
                    //游戏中才调用
                    repaint();
                }
                //失败重启
                if(state == 5){
                    state = 0;
                    resetGame();
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        //绘制提示语
        public void prompt(Graphics g) {
           ...
            //游戏失败
            if (state == 3) {
                g.fillRect(120, 240, 400, 70);
                GameUtils.drawWord(g, "失败,按空格键重新开始", Color.red, 35, 150, 290);
            }
    
        }
    
        ...
        //游戏重置
        public void resetGame(){
            //关闭当前窗口
            this.dispose();
            //开启新的窗口
            String[] args = {};
            main(args);
        }
    	...
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    在HeadObj类中修改分数设值

    @Override
    public void printSelf(Graphics g) {
        super.printSelf(g);
        //蛇吃食物
        Integer newX = null;
        Integer newY = null;
        FoodObj food = this.gameWin.food;
        if (this.x == food.x && this.y == food.y) {
            this.gameWin.food = food.getFood();
            BodyObj lastBody =
                    this.gameWin.bodyObjList.get(this.gameWin.bodyObjList.size() - 1);
            newX = lastBody.x;
            newY = lastBody.y;
            //分数+1
            this.gameWin.score++;
        }
    
        //通过判断
        if (this.gameWin.score >= 15) {
            //通过
            GameWin.state = 4;
        }
    
        move();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    20 游戏关卡的设置

    在GameUtils类添加关卡参数

    //关卡
    public static int level = 1;
    
    • 1
    • 2

    在GameWin类添加通关绘制

    public class GameWin extends JFrame {
    
        //分数
        public int score = 0;
        //窗口宽高
        int winWidth = 800;
        int winHeight = 600;
        //游戏状态 0:未开始 1:游戏中 2:暂停 3:失败 4:通过 5:失败后重启 6:下一关
        public static int state = 0;
        
    
        public void launch() {
            ....
    
            //键盘事件
            this.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                        switch (state) {
                            case 0://未开始
                                state = 1;//游戏中
                                break;
                            case 1://游戏中
                                state = 2;//暂停
                                repaint();
                                break;
                            case 2://暂停
                                state = 1;//游戏中
                                break;
                            case 3://游戏失败
                                state = 5;//失败后重新开始
                                break;
                            case 4://游戏通关
                                state = 6;//下一关
                                break;
                            default:
                                break;
                        }
                    }
                }
            });
    
            while (true) {
                if (state == 1) {
                    //游戏中才调用
                    repaint();
                }
                //失败重启
                if(state == 5){
                    state = 0;
                    resetGame();
                }
                //游戏通下一关 设置成3关
                if(state == 6 && GameUtils.level != 3){
                    state = 1;
                    GameUtils.level++;
                    resetGame();
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
       ...
    
        //绘制提示语
        public void prompt(Graphics g) {
            ...
            //通关
            if (state == 4) {
                g.fillRect(120, 240, 400, 70);
                if(GameUtils.level == 3){
                    GameUtils.drawWord(g, "达成条件,游戏通关", Color.green, 35, 150, 290);
                }else {
                    GameUtils.drawWord(g, "达成条件,按空格键下一关", Color.green, 35, 150, 290);
                }
    
            }
        }
    
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
  • 相关阅读:
    eureka
    2023年中国云计算软件市场规模、市场结构及市场份额情况分析[图]
    webpack优化系列五:vue项目配置 webpack-obfuscator 进行代码加密混淆
    【无标题】
    线扫相机设置编码器触发
    智能语法编辑器市场现状及未来发展趋势分析
    编译器一日一练(DIY系列之语义分析)
    程序员周刊(第4期):程序员的财富观
    以全新的视角审视重构——世界软件大师“鲍勃大叔”作序推荐
    idea在controller或者service使用ctrl+alt+b进入方法后,如何返回到 进入前的那一层
  • 原文地址:https://blog.csdn.net/weixin_42469070/article/details/127597091