Java小游戏之贪吃蛇

news2024/11/23 18:56:08

文章目录

  • 一:窗口的绘制
    • 1.1 定义窗口类——SnakeGame
    • 1.2 设置窗口的参数
    • 1.3 启动main方法
  • 二:窗口网格的绘制
    • 2.1 重写paint方法
      • 2.1.1 为什么要重写paint方法
      • 2.1.2 实现方式
    • 2.2 Graphics
    • 2.3 设置网格线的参数
  • 三:游戏物体父类的创建——SnakeEntity
  • 四:游戏工具类的创建——SnakeUtil
    • 4.1 获取蛇头的图片
    • 4.2 获取蛇身的图片
    • 4.3 获取食物的图片
    • 4.4 绘制文字
  • 五:蛇头部的绘制——SnakeHeadEntity
    • 5.1 设置蛇头的方向
    • 5.2 绘制自身
  • 六:蛇头的简单移动
    • 6.1 在HeadObj添加move方法
    • 6.2 在paintSelf方法中添加move方法
    • 6.3 蛇的重复移动需要调用repaint()方法
  • 七:键盘控制蛇的方向
    • 7.1 在SnakeHeadEntity中添加键盘监听事件
    • 7.2 编写changeDirection方法
  • 八:蛇越界后的处理
    • 1.编写checkIndex()方法
    • 2.在paintSelf方法中添加checkIndex()方法
  • 九:蛇身的添加和移动
    • 9.1 新建蛇身实体类——SnakeBodyEntity
    • 9.2 在SnakeGame定义蛇身集合
    • 9.3 在launch()方法对蛇身进行初始化
    • 9.4 在paint方法绘制蛇身体
    • 9.5 在move方法中添加身体移动逻辑
  • 十:食物的随机生成
    • 10.1 新建食物实体类——SnakeFoodEntity
    • 10.2 获取食物
    • 10.3 在SnakeGame中添加食物实体类
    • 10.4 在paint中绘制食物
  • 十一:蛇吃食物和食物的重新生成
    • 11.1 在SnakeHeadEntity中的paintSelf添加获取食物的对象
    • 11.2 判断蛇头和食物是否重合
  • 十二:蛇的增长
    • 12.1 定义身体最后一节的坐标
    • 12.2 在move方法后添加元素
    • 12.3 修改move方法的遍历顺序
  • 十三:计分面板的编写
    • 13.1 在SnakeGame定义窗口的宽高
    • 13.2 定义游戏分数,并且在paint绘制出来
    • 13.3 蛇吃食物,分数加一
  • 十四:游戏开始的提示语
    • 14.1 在SnakeGame定义游戏状态
    • 14.2 在while语句中添加判断,只有状态为1,才需要重复执行repaint()方法
    • 14.3 绘制提示语
    • 14.4 在paint方法添加提示语
  • 十五:游戏开始和暂停的键盘事件以及通关判断
    • 15.1 在SnakeGame的launch方法添加键盘函数
    • 15.2 通关判断
    • 15.3 添加通关提示语
  • 十六:蛇和身体碰撞判断
    • 16.1 在move方法中添加代码
    • 16.2 在prompt方法中添加游戏失败的提示语
  • 十七:双缓存解决画面闪烁
  • 十八:游戏失败后重新开始
    • 18.1 SnakeGame添加resetGame方法
    • 18.2 修改Switch语句
  • 十九:源码奉上
    • 19.1 SnakeGame
    • 19.2 SnakeUtil
    • 19.3 SnakeEntity
    • 19.4 SnakeHeadEntity
    • 19.5 SnakeBodyEntity
    • 19.6 SnakeFoodEntity

一:窗口的绘制

1.1 定义窗口类——SnakeGame

import javax.swing.*;

public class SnakeGame extends JFrame {

}

1.2 设置窗口的参数

import javax.swing.*;

public class SnakeGame extends JFrame {
    public void launch(){
        //设置窗口是否可见
        this.setVisible(true);
        //设置窗口的大小
        this.setSize(600,600);
        //设置窗口的位置在屏幕上居中
        this.setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");
    }

    public static void main(String[] args) {
        GameWin gameWin = new GameWin();
        gameWin.launch();
    }
}

1.3 启动main方法

![在这里插入图片描述](https://img-blog.csdnimg.cn/84d5e157e3c143979e31c11c3c9efc53.png

二:窗口网格的绘制

	@Override
    public void paint(Graphics g) {
        //灰色背景
        g.setColor(Color.gray);
        //绘制矩形,和窗口一样,宽和高都是600
        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);
        }
    }

2.1 重写paint方法

2.1.1 为什么要重写paint方法

当我们使用JFrame创建出窗体时,遇到窗体的尺寸改变(ie.拉伸窗体),或者窗体的部分像素被移动到屏幕之外,都会导致窗体的刷新。窗体有一个系统自带的刷新方法。但这时如果窗体中有此前绘制出的图像,则图像会随窗体的刷新而消失,这时候我们就需要将绘制图像的方法重写入JFrame的paint方法中,让图像随窗体的刷新而同步再次被绘制出来。

2.1.2 实现方式

函数要在类继承JFrame或者JPanel两个属性下才能实现重写,并且这个方法是系统自动调用的。
重写绘制方法的本质是将图像数据化、对象化。将图像的属性(eg. 坐标、颜色、图形类型……)和其绘制方法写入paint()。

2.2 Graphics

  1. ​实际生活中如果需要画图,首先我们得准备一张纸,然后在拿一支画笔,配和一些颜色,就可以在纸上画出来各种各样的图形,例如圆圈、矩形等等。

  2. 程序中绘图也一样,也需要画布,画笔,颜料等等。AWT中提供了Canvas类充当画布,提供了Graphics类来充当画笔,通过调用Graphics对象的setColor()方法可以给画笔设置颜色。

2.3 设置网格线的参数

		//灰色背景
        g.setColor(Color.gray);
        //绘制矩形,和窗口一样,宽和高都是600
        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);
        }

在这里插入图片描述

三:游戏物体父类的创建——SnakeEntity

import com.sysg.game.sanke.SnakeGame;
import java.awt.*;

public class SnakeEntity{

    //图片
    Image img;
    //坐标
    int x;
    int y;
    //宽高
    int width = 30;
    int height = 30;
    //窗口类的引用
    GameWin frame;

    public Image getImg() {
        return img;
    }

    public void setImg(Image img) {
        this.img = img;
    }

    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 getFrame() {
        return frame;
    }

    public void setFrame(GameWin frame) {
        this.frame = frame;
    }

    public SnakeEntity() {
    }

    public SnakeEntity(Image img, int x, int y, int width, int height, GameWin frame) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.frame = frame;
    }

    //绘制自身
    public void paintSelf(Graphics g){
        g.drawImage(img,x,y,null);
    }
}

四:游戏工具类的创建——SnakeUtil

import java.awt.*;
public class SnakeUtil{
    //蛇头
    public static Image upImg = Toolkit.getDefaultToolkit().getImage("img/up.png");
    public static Image downImg = Toolkit.getDefaultToolkit().getImage("img/down.png");
    public static Image leftImg = Toolkit.getDefaultToolkit().getImage("img/left.png");
    public static Image rightImg = Toolkit.getDefaultToolkit().getImage("img/right.png");
    //蛇身
    public static Image bodyImg = Toolkit.getDefaultToolkit().getImage("img/body.png");
    //食物
    public static Image foodImg = Toolkit.getDefaultToolkit().getImage("img/food.png");

    //绘制文字
    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);
    }
}

4.1 获取蛇头的图片

	public static Image upImg = Toolkit.getDefaultToolkit().getImage("img/up.png");
    public static Image downImg = Toolkit.getDefaultToolkit().getImage("img/down.png");
    public static Image leftImg = Toolkit.getDefaultToolkit().getImage("img/left.png");
    public static Image rightImg = Toolkit.getDefaultToolkit().getImage("img/right.png");

4.2 获取蛇身的图片

public static Image bodyImg = Toolkit.getDefaultToolkit().getImage("img/body.png");

4.3 获取食物的图片

public static Image foodImg = Toolkit.getDefaultToolkit().getImage("img/food.png");

4.4 绘制文字

	//绘制文字
    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);
    }

五:蛇头部的绘制——SnakeHeadEntity

import java.awt.*;

public class SnakeHeadEntity extends SnakeEntity{
    //方向 up down left right
    private String direction = "right";

    public String getDirection() {
        return direction;
    }

    public void setDirection(String direction) {
        this.direction = direction;
    }

    public SnakeHeadEntity (Image img, int x, int y, GameWin frame) {
        super(img, x, y, frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}

5.1 设置蛇头的方向

//方向 up down left right
private String direction = "right";

默认蛇头的方向是向右的!

5.2 绘制自身

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }

在这里插入图片描述

六:蛇头的简单移动

6.1 在HeadObj添加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;
        }

    }

6.2 在paintSelf方法中添加move方法

@Override
    public void paintSelf(Graphics g) {
        //设置蛇头的位置
        super.paintSelf(g);
        //移动蛇头
        move();
    }

6.3 蛇的重复移动需要调用repaint()方法

 /**
     * 窗口的绘制
     */
    public void launch(){
        //设置窗口是否可见、默认是false不可见
        this.setVisible(true);
        //设置窗口的大小
        this.setSize(winWidth,winHeight);
        //设置窗口的位置在屏幕居中
        this.setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");  
        //移动蛇头
        while(true){
           // repaint()方法是一个具有刷新页面效果的方法,若不调用repaint方法图形发生变化后不会立刻显示
           repaint();
            try {
                //一秒会调用五次
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

七:键盘控制蛇的方向

7.1 在SnakeHeadEntity中添加键盘监听事件

public SnakeHeadEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
        //监听键盘
        this.frame.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //控制蛇头的移动
                changeDirection(e);
            }
        });
    }

7.2 编写changeDirection方法

   /**
     * 控制蛇头的移动
     * w->a->s->d
     */
    public void changeDirection(KeyEvent e) {
        switch (e.getKeyCode()){
            //按下A键->朝左移动
            case KeyEvent.VK_A:
                if(!"right".equals(direction)){
                    //将方向改为左边
                    direction = "left";
                    //修改蛇头图片的方向
                    img = SnakeUtil.leftSnakeHeadImg;
                }
                break;

            //按下D键->朝右移动
            case KeyEvent.VK_D:
                if(!"left".equals(direction)){
                    //将方向改为右边
                    direction = "right";
                    //修改蛇头图片的方向
                    img = SnakeUtil.rightSnakeHeadImg;
                }
                break;

            //按下W键->朝上移动
            case KeyEvent.VK_W:
                if(!"down".equals(direction)){
                    //将方向改为上边
                    direction = "up";
                    //修改蛇头图片的方向
                    img = SnakeUtil.upSnakeHeadImg;
                }
                break;

            //按下S键->朝下移动
            case KeyEvent.VK_S:
                if(!"up".equals(direction)){
                    //将方向改为上边
                    direction = "down";
                    //修改蛇头图片的方向
                    img = SnakeUtil.downSnakeHeadImg;
                }
                break;
            default:
                break;
        }

    }

八:蛇越界后的处理

1.编写checkIndex()方法

注:标题栏高度为30,所以y<30,不是y<0

/**
     * 贪吃蛇的越界处理
     */
    public void checkIndex(){
        if(x < 0){
            x = 570;
        } else if (x > 570){
            x = 0;
        } else if (y < 30){
            y = 570;
        } else if (y > 570){
            y = 30;
        }
    }

2.在paintSelf方法中添加checkIndex()方法

@Override
    public void paintSelf(Graphics g) {
        //设置蛇头的位置
        super.paintSelf(g);
        //移动蛇头
        move();
        checkIndex();
    }

九:蛇身的添加和移动

9.1 新建蛇身实体类——SnakeBodyEntity

/**
 * 蛇身体
 */
public class SnakeBodyEntity extends SnakeEntity {

    public SnakeBodyEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}

9.2 在SnakeGame定义蛇身集合

/**
* 蛇身集合
*/
public List snakeBodyEntityList = new ArrayList<>();

9.3 在launch()方法对蛇身进行初始化

//蛇身初始化
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,30,570,this));
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,0,570,this));

9.4 在paint方法绘制蛇身体

防止身体重叠,所以进行反向遍历

//绘制蛇身体
        for (int i = snakeBodyEntityList.size() - 1; i >= 0; i--) {
            snakeBodyEntityList.get(i).paintSelf(graphicsImage);
        }

9.5 在move方法中添加身体移动逻辑

//蛇身体的移动
        List<SnakeBodyEntity> snakeBodyEntityList = this.frame.snakeBodyEntityList;
        for (int i = snakeBodyEntityList.size() - 1; i >= 1; i--) {
            //蛇的移动就是上一个坐标和当前坐标相等
            snakeBodyEntityList.get(i).x = snakeBodyEntityList.get(i-1).x;
            snakeBodyEntityList.get(i).y = snakeBodyEntityList.get(i-1).y;
        }

十:食物的随机生成

食物的坐标需要满足x->(0-570),y->(30,570)并且是30的倍数

10.1 新建食物实体类——SnakeFoodEntity

/**
 * 食物实体类
 */
public class SnakeFoodEntity extends SnakeEntity {

    /**
     * 随机
     */
    Random r = new Random();

    public SnakeFoodEntity() {
        super();
    }

    public SnakeFoodEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
    }

    /**
     * 获取食物
     * x:0->570
     * y.3:0->570
     * @return
     */
    public SnakeFoodEntity getFood(){
        return new SnakeFoodEntity(SnakeUtil.snakeFoodImg,r.nextInt(20) * 30,(r.nextInt(19) + 1) * 30,this.frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}

10.2 获取食物

/**
     * 获取食物
     * x:0->570
     * y.3:0->570
     * @return
     */
    public SnakeFoodEntity getFood(){
        return new SnakeFoodEntity(SnakeUtil.snakeFoodImg,r.nextInt(20) * 30,(r.nextInt(19) + 1) * 30,this.frame);
    }

10.3 在SnakeGame中添加食物实体类

   /**
     * 食物
     */
    public SnakeFoodEntity snakeFoodEntity = new SnakeFoodEntity().getFood();

10.4 在paint中绘制食物

    //食物绘制
    snakeFoodEntity.paintSelf(g);

十一:蛇吃食物和食物的重新生成

11.1 在SnakeHeadEntity中的paintSelf添加获取食物的对象

     //食物
    SnakeFoodEntity snakeFoodEntity = this.frame.snakeFoodEntity;

注:此方法需要放在move()之前

11.2 判断蛇头和食物是否重合

if(this.x == snakeFoodEntity.x && this.y == snakeFoodEntity.y ){
     //此时蛇头和食物重合了
     this.frame.snakeFoodEntity = snakeFoodEntity.getFood();
 }

十二:蛇的增长

蛇的增长本质就是给蛇身添加一个元素,根据集合的最后一个位置确定

12.1 定义身体最后一节的坐标

//身体最后一节的坐标
        Integer newX = null;
        Integer newY = null;
        if(this.x == snakeFoodEntity.x && this.y == snakeFoodEntity.y ){
            //此时蛇头和食物重合了
            this.frame.snakeFoodEntity = snakeFoodEntity.getFood();
            //获取蛇身的最后一个元素
            SnakeBodyEntity lastSnakeBodyEntity = this.frame.snakeBodyEntityList.get(this.frame.snakeBodyEntityList.size() - 1);
            newX = lastSnakeBodyEntity.x;
            newY = lastSnakeBodyEntity.y;
           
        }

12.2 在move方法后添加元素

if(newX != null && newY != null){
   this.frame.snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,newX,newY,this.frame));
}

12.3 修改move方法的遍历顺序

 /**
     * 蛇的移动
     * 蛇身体的移动的代码一定要写在蛇头移动的前面
     */
    public void  move(){
        //蛇身体的移动
        List<SnakeBodyEntity> snakeBodyEntityList = this.frame.snakeBodyEntityList;
        for (int i = snakeBodyEntityList.size() - 1; i >= 1; i--) {
            //蛇的移动就是上一个坐标和当前坐标相等
            snakeBodyEntityList.get(i).x = snakeBodyEntityList.get(i-1).x;
            snakeBodyEntityList.get(i).y = snakeBodyEntityList.get(i-1).y;
        }
        snakeBodyEntityList.get(0).x = this.x;
        snakeBodyEntityList.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;
        }

    }

十三:计分面板的编写

13.1 在SnakeGame定义窗口的宽高

//窗口宽高
int winWidth = 800;
int winHeight = 600;

注:将之前定义的600,600替换为winWidth ,winHeight

13.2 定义游戏分数,并且在paint绘制出来

//当前分数
public int score = 0;

//分数绘制
SnakeUtil.drawWord(graphicsImage,score  +"分" , Color.BLUE , 50,650,330);

13.3 蛇吃食物,分数加一

在SnakeHeadEntity的paintSelf添加对应方法

@Override
    public void paintSelf(Graphics g) {
        //设置蛇头的位置
        super.paintSelf(g);
        //食物
        SnakeFoodEntity snakeFoodEntity = this.frame.snakeFoodEntity;
        //身体最后一节的坐标
        Integer newX = null;
        Integer newY = null;
        if(this.x == snakeFoodEntity.x && this.y == snakeFoodEntity.y ){
            //此时蛇头和食物重合了
            this.frame.snakeFoodEntity = snakeFoodEntity.getFood();
            //获取蛇身的最后一个元素
            SnakeBodyEntity lastSnakeBodyEntity = this.frame.snakeBodyEntityList.get(this.frame.snakeBodyEntityList.size() - 1);
            newX = lastSnakeBodyEntity.x;
            newY = lastSnakeBodyEntity.y;
            //分数+1
            this.frame.score ++;
        }
        //移动蛇头
        move();
        if(newX != null && newY != null){
            this.frame.snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,newX,newY,this.frame));
        }
        //贪吃蛇的越界处理,移动后新的身体对象添加到snakeBodyEntityList
        checkIndex();
    }

十四:游戏开始的提示语

14.1 在SnakeGame定义游戏状态

//游戏状态 0-未开始 1-游戏中 2-暂停 3-失败 4-通关 5-失败后重启 6-下一关
    public static int state = 0;

14.2 在while语句中添加判断,只有状态为1,才需要重复执行repaint()方法

/**
     * 窗口的绘制
     */
    public void launch(){
        //设置窗口是否可见、默认是false不可见
        this.setVisible(true);
        //设置窗口的大小
        this.setSize(winWidth,winHeight);
        //设置窗口的位置在屏幕居中
        this.setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");
        //蛇身初始化
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,30,570,this));
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,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;
                        case 3:
                            //失败后重启
                            state = 5;
                            break;

                        case 4:
                            //游戏通关,进入下一关
                            state = 6;
                            break;
                        default:
                            break;

                    }
                }
            }
        });
        //移动蛇头
        while(true){
            //只有状态为游戏中,才需要反复执行repaint()方法
            if(state == 1){
                // repaint()方法是一个具有刷新页面效果的方法,若不调用repaint方法图形发生变化后不会立刻显示
                repaint();
            }
            try {
                //一秒会调用五次
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

14.3 绘制提示语

/**
     * 绘制提示语
     * @param g
     */
    void prompt(Graphics g){
        //未开始
        if(state == 0){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);
        }
      
    }

14.4 在paint方法添加提示语

/**
     * 绘制
     * @param g
     */
    @Override
    public void paint(Graphics g){
       

        //灰色背景
        g.setColor(Color.gray);
        //绘制矩形,和窗口一样,宽和高都是600
        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 = snakeBodyEntityList.size() - 1; i >= 0; i--) {
            snakeBodyEntityList.get(i).paintSelf(g);
        }
        //绘制蛇头
        snakeHeadEntity.paintSelf(g);
        //食物绘制
        snakeFoodEntity.paintSelf(g);
        //关卡绘制
        SnakeUtil.drawWord(g,"第"+SnakeUtil.level+"关",Color.orange,40,650,260);
        //分数绘制
        SnakeUtil.drawWord(g,score  +"分" , Color.BLUE , 50,650,330);
        //绘制提示语
        g.setColor(Color.gray);
        prompt(g);
    }

在这里插入图片描述

十五:游戏开始和暂停的键盘事件以及通关判断

15.1 在SnakeGame的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;

                    }
                }
            }
        });

15.2 通关判断

在SnakeHeadEntity的paintSelf中添加

//通关判断
        if(this.frame.score >= 3){
            //通关
            SnakeGame.state = 4;
        }

15.3 添加通关提示语

/**
     * 绘制提示语
     * @param g
     */
    void prompt(Graphics g){
        //未开始
        if(state == 0){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);
        }

        //游戏暂停
        if(state == 2){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);
        }

        //通关
        if(state == 4){
            g.fillRect(120,240,400,70);
            if(SnakeUtil.level == 3){
                SnakeUtil.drawWord(g,"达成条件,游戏通关",Color.green,35,150,290);
            } else {
                SnakeUtil.drawWord(g,"达成条件,点击空格开始下一关",Color.green,35,150,290);
            }

        }
    }

十六:蛇和身体碰撞判断

16.1 在move方法中添加代码

//蛇头和身体碰撞判断
            if(this.x == snakeBodyEntityList.get(i).x && this.y == snakeBodyEntityList.get(i).y){
                //蛇咬到自己,失败
                SnakeGame.state = 3;
            }

16.2 在prompt方法中添加游戏失败的提示语

//失败
        if(state == 3){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"失败,按下空格重新开始",Color.red,35,150,290);
        }

十七:双缓存解决画面闪烁

原因:每次刷新都是重新绘制图片

//定义双缓存图片
    Image offScreenImage = null;
/**
     * 绘制
     * @param g
     */
    @Override
    public void paint(Graphics g){
        //初始化双缓存图片
        if(offScreenImage == null){
            offScreenImage = this.createImage(winWidth,winHeight);
        }
        //获取图片对应的Graphics对象
        Graphics graphicsImage = offScreenImage.getGraphics();

        //灰色背景
        graphicsImage.setColor(Color.gray);
        //绘制矩形,和窗口一样,宽和高都是600
        graphicsImage.fillRect(0,0,winWidth,winHeight);
        //网格线颜色
        graphicsImage.setColor(Color.black);
        //绘制网格线
        for (int i = 0; i <= 20 ; i++) {
            //横线
            graphicsImage.drawLine(0,i * 30,600,i * 30);
            //竖线
            graphicsImage.drawLine(i * 30,0,i * 30,600);
        }
        //绘制蛇身体
        for (int i = snakeBodyEntityList.size() - 1; i >= 0; i--) {
            snakeBodyEntityList.get(i).paintSelf(graphicsImage);
        }
        //绘制蛇头
        snakeHeadEntity.paintSelf(graphicsImage);
        //食物绘制
        snakeFoodEntity.paintSelf(graphicsImage);
        //关卡绘制
        SnakeUtil.drawWord(graphicsImage,"第"+SnakeUtil.level+"关",Color.orange,40,650,260);
        //分数绘制
        SnakeUtil.drawWord(graphicsImage,score  +"分" , Color.BLUE , 50,650,330);
        //绘制提示语
        graphicsImage.setColor(Color.gray);
        prompt(graphicsImage);
        //将双缓存图片绘制到主窗口中
        g.drawImage(offScreenImage,0,0,null);
    }

十八:游戏失败后重新开始

18.1 SnakeGame添加resetGame方法

/**
     * 失败后,重置游戏
     */
    void resetGame(){
        //关闭当前窗口

        //开启新的窗口
        String[] args = {};
        main(args);

    }

18.2 修改Switch语句

/**
     * 窗口的绘制
     */
    public void launch(){
        //设置窗口是否可见、默认是false不可见
        this.setVisible(true);
        //设置窗口的大小
        this.setSize(winWidth,winHeight);
        //设置窗口的位置在屏幕居中
        this.setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");
        //蛇身初始化
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,30,570,this));
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,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;
                        case 3:
                            //失败后重启
                            state = 5;
                            break;

                        case 4:
                            //游戏通关,进入下一关
                            state = 6;
                            break;
                        default:
                            break;

                    }
                }
            }
        });
        //移动蛇头
        while(true){
            //只有状态为游戏中,才需要反复执行repaint()方法
            if(state == 1){
                // repaint()方法是一个具有刷新页面效果的方法,若不调用repaint方法图形发生变化后不会立刻显示
                repaint();
            }
            //失败重启
            if(state == 5){
                state = 0;
                resetGame();
            }
            //进入下一关
            if(state == 6 && SnakeUtil.level != 3){
                state = 1;
                SnakeUtil.level++;
                resetGame();
            }
            try {
                //一秒会调用五次
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

十九:源码奉上

19.1 SnakeGame

package com.sysg.game.sanke;

import com.sysg.game.sanke.entity.SnakeBodyEntity;
import com.sysg.game.sanke.entity.SnakeFoodEntity;
import com.sysg.game.sanke.entity.SnakeHeadEntity;
import com.sysg.game.sanke.utils.SnakeUtil;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ikun
 */
public class SnakeGame extends JFrame {

    //定义双缓存图片
    Image offScreenImage = null;

    //游戏状态 0-未开始 1-游戏中 2-暂停 3-失败 4-通关 5-失败后重启 6-下一关
    public static int state = 0;


    //当前分数
    public int score = 0;

    //窗口宽高
    int winWidth = 800;
    int winHeight = 600;


    /**
     * 创建蛇头对象
     * 默认为右边、坐标为30,570、窗口为当前this
     */
    SnakeHeadEntity snakeHeadEntity = new SnakeHeadEntity(SnakeUtil.rightSnakeHeadImg,60,570,this);

    /**
     * 蛇身集合
     */
    public List<SnakeBodyEntity> snakeBodyEntityList = new ArrayList<>();

    /**
     * 食物
     */
    public SnakeFoodEntity snakeFoodEntity = new SnakeFoodEntity().getFood();

    /**
     * 窗口的绘制
     */
    public void launch(){
        //设置窗口是否可见、默认是false不可见
        this.setVisible(true);
        //设置窗口的大小
        this.setSize(winWidth,winHeight);
        //设置窗口的位置在屏幕居中
        this.setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");
        //蛇身初始化
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,30,570,this));
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,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;
                        case 3:
                            //失败后重启
                            state = 5;
                            break;

                        case 4:
                            //游戏通关,进入下一关
                            state = 6;
                            break;
                        default:
                            break;

                    }
                }
            }
        });
        //移动蛇头
        while(true){
            //只有状态为游戏中,才需要反复执行repaint()方法
            if(state == 1){
                // repaint()方法是一个具有刷新页面效果的方法,若不调用repaint方法图形发生变化后不会立刻显示
                repaint();
            }
            //失败重启
            if(state == 5){
                state = 0;
                resetGame();
            }
            //进入下一关
            if(state == 6 && SnakeUtil.level != 3){
                state = 1;
                SnakeUtil.level++;
                resetGame();
            }
            try {
                //一秒会调用五次
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 绘制
     * @param g
     */
    @Override
    public void paint(Graphics g){
        //初始化双缓存图片
        if(offScreenImage == null){
            offScreenImage = this.createImage(winWidth,winHeight);
        }
        //获取图片对应的Graphics对象
        Graphics graphicsImage = offScreenImage.getGraphics();

        //灰色背景
        graphicsImage.setColor(Color.gray);
        //绘制矩形,和窗口一样,宽和高都是600
        graphicsImage.fillRect(0,0,winWidth,winHeight);
        //网格线颜色
        graphicsImage.setColor(Color.black);
        //绘制网格线
        for (int i = 0; i <= 20 ; i++) {
            //横线
            graphicsImage.drawLine(0,i * 30,600,i * 30);
            //竖线
            graphicsImage.drawLine(i * 30,0,i * 30,600);
        }
        //绘制蛇身体
        for (int i = snakeBodyEntityList.size() - 1; i >= 0; i--) {
            snakeBodyEntityList.get(i).paintSelf(graphicsImage);
        }
        //绘制蛇头
        snakeHeadEntity.paintSelf(graphicsImage);
        //食物绘制
        snakeFoodEntity.paintSelf(graphicsImage);
        //关卡绘制
        SnakeUtil.drawWord(graphicsImage,"第"+SnakeUtil.level+"关",Color.orange,40,650,260);
        //分数绘制
        SnakeUtil.drawWord(graphicsImage,score  +"分" , Color.BLUE , 50,650,330);
        //绘制提示语
        graphicsImage.setColor(Color.gray);
        prompt(graphicsImage);
        //将双缓存图片绘制到主窗口中
        g.drawImage(offScreenImage,0,0,null);
    }

    /**
     * 绘制提示语
     * @param g
     */
    void prompt(Graphics g){
        //未开始
        if(state == 0){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);
        }

        //游戏暂停
        if(state == 2){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);
        }


        //失败
        if(state == 3){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"失败,按下空格重新开始",Color.red,35,150,290);
        }

        //通关
        if(state == 4){
            g.fillRect(120,240,400,70);
            if(SnakeUtil.level == 3){
                SnakeUtil.drawWord(g,"达成条件,游戏通关",Color.green,35,150,290);
            } else {
                SnakeUtil.drawWord(g,"达成条件,点击空格开始下一关",Color.green,35,150,290);
            }

        }
    }

    /**
     * 失败后,重置游戏
     */
    void resetGame(){
        //关闭当前窗口

        //开启新的窗口
        String[] args = {};
        main(args);

    }

    public static void main(String[] args) {
        SnakeGame snakeGame = new SnakeGame();
        snakeGame.launch();
    }



}


19.2 SnakeUtil

package com.sysg.game.sanke.utils;

import java.awt.*;

/**
 * 贪吃蛇工具类
 * @author ikun
 */
public class SnakeUtil {

    //蛇头
    public static Image upSnakeHeadImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/up.png");
    public static Image downSnakeHeadImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/down.png");
    public static Image rightSnakeHeadImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/right.png");
    public static Image leftSnakeHeadImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/left.png");
    //蛇身
    public static Image snakeBodyImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/body.png");
    //食物
    public static Image snakeFoodImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/food.png");
    //关卡,默认是第一关
    public static int level = 1;




    /**
     * 绘制文字
     * @param g 绘图的实体类
     * @param str 字符串的内容
     * @param color 字符串的颜色
     * @param strFontSize 字符串的字体大小
     * @param x 字符串的横坐标
     * @param y 字符串的纵坐标
     */
    public static void drawWord(Graphics g,String str,Color color,int strFontSize,int x,int y){
        g.setColor(color);
        //设置字体样式,Font.BOLD->粗体
        g.setFont(new Font("仿宋",Font.BOLD,strFontSize));
        //将文字绘制到屏幕上
        g.drawString(str,x,y);
    }


}


19.3 SnakeEntity

package com.sysg.game.sanke.entity;

import com.sysg.game.sanke.SnakeGame;

import java.awt.*;

/**
 * 贪吃蛇实体类
 */
public class SnakeEntity {

    //物体的图片
    Image img;

    //物体的坐标
    int x,y;

    //物体的宽高,都为30,与方格保持一致
    int width = 30,height = 30;

    //窗口类的引用
    SnakeGame frame;

    public Image getImg() {
        return img;
    }

    public void setImg(Image img) {
        this.img = img;
    }

    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 SnakeGame getFrame() {
        return frame;
    }

    public void setFrame(SnakeGame frame) {
        this.frame = frame;
    }

    /**
     * 有参构造
     * @param img
     * @param x
     * @param y
     * @param frame
     */
    public SnakeEntity(Image img, int x, int y, SnakeGame frame) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.frame = frame;
    }

    /**
     * 有参构造
     * @param img
     * @param x
     * @param y
     * @param width
     * @param height
     * @param frame
     */
    public SnakeEntity(Image img, int x, int y, int width, int height, SnakeGame frame) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.frame = frame;
    }

    /**
     * 无参构造
     */
    public SnakeEntity() {
    }

    //绘制自身的方法
    public void paintSelf(Graphics g){
        g.drawImage(img,x,y,null);
    }
}


19.4 SnakeHeadEntity

package com.sysg.game.sanke.entity;

import com.sysg.game.sanke.SnakeGame;
import com.sysg.game.sanke.utils.SnakeUtil;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;

/**
 * 蛇头实体类
 * @author ikun
 */
public class SnakeHeadEntity extends SnakeEntity{
    /**
     * 蛇头方向 up down left right
     * 默认为right
     */
    private String direction = "right";

    public String getDirection() {
        return direction;
    }

    public void setDirection(String direction) {
        this.direction = direction;
    }

    public SnakeHeadEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
        //监听键盘
        this.frame.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //控制蛇头的移动
                changeDirection(e);
            }
        });
    }

    /**
     * 控制蛇头的移动
     * w->a->s->d
     */
    public void changeDirection(KeyEvent e) {
        switch (e.getKeyCode()){
            //按下A键->朝左移动
            case KeyEvent.VK_A:
                if(!"right".equals(direction)){
                    //将方向改为左边
                    direction = "left";
                    //修改蛇头图片的方向
                    img = SnakeUtil.leftSnakeHeadImg;
                }
                break;

            //按下D键->朝右移动
            case KeyEvent.VK_D:
                if(!"left".equals(direction)){
                    //将方向改为右边
                    direction = "right";
                    //修改蛇头图片的方向
                    img = SnakeUtil.rightSnakeHeadImg;
                }
                break;

            //按下W键->朝上移动
            case KeyEvent.VK_W:
                if(!"down".equals(direction)){
                    //将方向改为上边
                    direction = "up";
                    //修改蛇头图片的方向
                    img = SnakeUtil.upSnakeHeadImg;
                }
                break;

            //按下S键->朝下移动
            case KeyEvent.VK_S:
                if(!"up".equals(direction)){
                    //将方向改为上边
                    direction = "down";
                    //修改蛇头图片的方向
                    img = SnakeUtil.downSnakeHeadImg;
                }
                break;
            default:
                break;
        }

    }

    /**
     * 蛇的移动
     * 蛇身体的移动的代码一定要写在蛇头移动的前面
     */
    public void  move(){
        //蛇身体的移动
        List<SnakeBodyEntity> snakeBodyEntityList = this.frame.snakeBodyEntityList;
        for (int i = snakeBodyEntityList.size() - 1; i >= 1; i--) {
            //蛇的移动就是上一个坐标和当前坐标相等
            snakeBodyEntityList.get(i).x = snakeBodyEntityList.get(i-1).x;
            snakeBodyEntityList.get(i).y = snakeBodyEntityList.get(i-1).y;
            //蛇头和身体碰撞判断
            if(this.x == snakeBodyEntityList.get(i).x && this.y == snakeBodyEntityList.get(i).y){
                //蛇咬到自己,失败
                SnakeGame.state = 3;
            }
        }
        snakeBodyEntityList.get(0).x = this.x;
        snakeBodyEntityList.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;
        }

    }


    @Override
    public void paintSelf(Graphics g) {
        //设置蛇头的位置
        super.paintSelf(g);
        //食物
        SnakeFoodEntity snakeFoodEntity = this.frame.snakeFoodEntity;
        //身体最后一节的坐标
        Integer newX = null;
        Integer newY = null;
        if(this.x == snakeFoodEntity.x && this.y == snakeFoodEntity.y ){
            //此时蛇头和食物重合了
            this.frame.snakeFoodEntity = snakeFoodEntity.getFood();
            //获取蛇身的最后一个元素
            SnakeBodyEntity lastSnakeBodyEntity = this.frame.snakeBodyEntityList.get(this.frame.snakeBodyEntityList.size() - 1);
            newX = lastSnakeBodyEntity.x;
            newY = lastSnakeBodyEntity.y;
            //分数+1
            this.frame.score ++;
        }
        //通关判断
        if(this.frame.score >= 3){
            //通关
            SnakeGame.state = 4;
        }

        //移动蛇头
        move();
        if(newX != null && newY != null){
            this.frame.snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,newX,newY,this.frame));
        }
        //贪吃蛇的越界处理,移动后新的身体对象添加到snakeBodyEntityList
        checkIndex();
    }

    /**
     * 贪吃蛇的越界处理
     */
    public void checkIndex(){
        if(x < 0){
            x = 570;
        } else if (x > 570){
            x = 0;
        } else if (y < 30){
            y = 570;
        } else if (y > 570){
            y = 30;
        }
    }


}


19.5 SnakeBodyEntity

package com.sysg.game.sanke.entity;

import com.sysg.game.sanke.SnakeGame;

import java.awt.*;

/**
 * 蛇身体
 */
public class SnakeBodyEntity extends SnakeEntity {

    public SnakeBodyEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}


19.6 SnakeFoodEntity

package com.sysg.game.sanke.entity;

import com.sysg.game.sanke.SnakeGame;
import com.sysg.game.sanke.utils.SnakeUtil;

import java.awt.*;
import java.util.Random;

/**
 * 食物实体类
 */
public class SnakeFoodEntity extends SnakeEntity {

    /**
     * 随机
     */
    Random r = new Random();

    public SnakeFoodEntity() {
        super();
    }

    public SnakeFoodEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
    }

    /**
     * 获取食物
     * x:0->570
     * y.3:0->570
     * @return
     */
    public SnakeFoodEntity getFood(){
        return new SnakeFoodEntity(SnakeUtil.snakeFoodImg,r.nextInt(20) * 30,(r.nextInt(19) + 1) * 30,this.frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/530707.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Swagger之集成与用法

简介 Swagger 是一个规范且完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务&#xff1b; 作用 1.接口的文档在线生成 2.功能测试 SpringBoot集成Swagger 1.创建一个普通的SpringBoot项目&#xff0c;支持web应用 2.pom中加入Maven依赖 <depe…

K8S的的就绪探针readinessProbe 和存活探针livenessProbe

就绪探针&#xff1a;readinessProbe 什么是readinessProbe readinessProbe&#xff1a; 当Pod需要开始接收流量时&#xff0c;“kubelet” 将定期检查 readinessProbe&#xff0c;如果该probe处于成功状态&#xff0c;则容器视为就绪&#xff0c;并将 Pod 标记为已就绪状态。…

栈的基本操作详细介绍 看了就会!!!

文章目录 栈的介绍栈的概念栈的结构 栈的实现&#xff08;动态数组实现&#xff09;初始化栈入栈出栈获取栈顶元素判断栈是否为空获取栈中有效元素的个数销毁栈 栈的介绍 栈的概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进…

机器学习期末复习 决策树相关

决策树基本原理&#xff1a;基于信息增益、增益率与基尼系数的划分选择&#xff0c;预剪枝与后剪枝&#xff0c;多变量决策树以及决策树优缺点概述 如何避免决策树过拟合&#xff1f; 预剪枝和后剪枝 预剪枝&#xff1a; 1.生成结点&#xff0c;根据信息增益选出最优划分属…

玩转Google开源C++单元测试框架Google Test系列(gtest)之八 - 打造自己的单元测试框架

一、前言 上一篇我们分析了gtest的一些内部实现&#xff0c;总的来说整体的流程并不复杂。本篇我们就尝试编写一个精简版本的C单元测试框架&#xff1a;nancytest &#xff0c;通过编写这个简单的测试框架&#xff0c;将有助于我们理解gtest。 二、整体设计 使用最精简的设计…

Docker下Gitlab配置私有证书

Docker下Gitlab配置私有证书 1 创建私有证书※2 内网穿透配置&#xff08;可选&#xff09;3 Gitlab 配置私有证书3.1 新增存储HTTPS证书文件夹3.2 启动容器3.3 开放HTTPS端口3.4 设置IP、端口3.5 配置邮箱3.6 让配置生效3.7 访问 1 创建私有证书 参考 制作HTTPS私有证书 —HT…

玩转Google开源C++单元测试框架Google Test系列(gtest)之三 - 事件机制

一、前言 gtest提供了多种事件机制&#xff0c;非常方便我们在案例之前或之后做一些操作。总结一下gtest的事件一共有3种&#xff1a; 1. 全局的&#xff0c;所有案例执行前后。 2. TestSuite级别的&#xff0c;在某一批案例中第一个案例前&#xff0c;最后一个案例执行后。…

【STM32】基础知识 第十四课 串口通信: 深入探究与应用

【STM32】基础知识 第十四课 串口通信: 深入探究与应用 概述串口通信的基本原理串行通信 & 并行通信串行通信并行通信串行 vs 并行 单工/半双工/全双工单工通信半双工通信全双工通信总结 同步通信/异步通信同步通信异步通信波特率 常见的串行通信接口STM32 串口配置STM32 串…

linux pl320 mbox控制器驱动分析-(3) pl320驱动代码分析

linux pl320 mbox控制器驱动分析-&#xff08;3&#xff09;pl320驱动代码分析 1 pl320 mbox控制器宏定义2 初始化接口3 ipc_handler mbox中断处理函数4 数据的收发4.1 数据发送4.2 数据接收4.3 中断发送接收测试代码 5 设置以及清除远端目的core5.1 设置远端目的core5.2 清除远…

中东地区DNSpionage安全事件分析

事件摘要 思科Talos公司最近发现了一个以影响.gov域名为攻击手段的安全事件&#xff0c;而此安全事件主要针对黎巴嫩和阿拉伯联合酋长国&#xff08;阿联酋&#xff09;以及一家私营的黎巴嫩航空公司。根据我们的研究&#xff0c;攻击者花费了许多时间来了解受害者的基础网络&…

第九章结构性模式—桥接模式

文章目录 桥接模式解决的问题概念结构 实例使用场景 结构型模式描述如何将类或对象按某种布局组成更大的结构&#xff0c;有以下两种&#xff1a; 类结构型模式&#xff1a;采用继承机制来组织接口和类。对象结构型模式&#xff1a;釆用组合或聚合来组合对象。 由于组合关系或…

【数据科学赛】评估大语言模型 #¥65000

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息由AI辅助创作&#xff0c;仅供参考 比赛名称 大语言模型评估[2] (见文末阅读原文) 大赛背景 本次竞赛希…

OTA实现设备升级方案

引言 空中下载技术&#xff08;Over-the-Air Technology&#xff0c; OTA&#xff09;是通过移动通信的空中接口实现对移动终端设备进行远程管理的技术。 该技术在IOT行业非常的重要&#xff0c;当随着市场上的产品越来越多&#xff0c;保有量也越来越多&#xff0c;随着时间…

MySQL 性能调优及生产实战篇(一)

前言数据建模方案、数据类型优化存储引擎选择合理使用范式、反范式字符集选择主键选择适当数据冗余适当拆分数据类型优化更小更好简单就好尽量避免 NULL具体优化细节整型字符、字符串类型datetime、timestamp枚举代替字符串类型特殊类型 索引优化索引用处索引分类技术名词 总结…

由浅入深RPC通信原理实战

目录 1 背景知识2 RPC概述3 RPC框架实现要点3.1 注册中心3.2 代理技术3.3 序列化技术3.4 RPC通信协议3.5 系统IO3.6 超时重试机制3.7 时间轮算法3.8 负载均衡策略3.9 熔断限流3.10 滑动窗口算法3.11 限流组件 1 背景知识 单体架构 RPC产生解决的问题&#xff1a; 序列化是指…

Ae:图层面板 - 视图选项

从图层面板 Layer Panel的“显示通道和色彩管理设置” Show Channel and Color Manage Settings按钮中可以选择各种视图模式&#xff0c;与 Alpha 通道相关的一些视图可直接通过图层面板左下方的按钮或者使用快捷键进行切换。 其它的视图选项&#xff08;图层面板的最下方一行&…

基于PyQt5的图形化界面开发——PyQt示例_扫雷

基于PyQt5的图形化界面开发——PyQt示例_扫雷 前言1. 效果演示2. minesweeper.py3.图片文件其他文章 前言 今天来学习PyQt5的示例&#xff0c;其中主要涉及到一些触发函数窗口切换函数。 操作系统&#xff1a;Windows10 专业版 开发环境&#xff1a;Pycahrm Comunity 2022.3…

三分钟了解Spring Boot启动原理

大家通常只需要给一个类添加一个SpringBootApplication 注解&#xff0c;然后再加一个main 方法里面固定的写法 SpringApplication.run(Application.class, args); 那么spring boot 到底是如何启动服务的呢。 接下来咱们通过源码解析。 Spring Boot 的启动原理可以概括为以下几…

一篇吃透布隆过滤器(Bloom Filter)及其使用场景

目录 1、什么是布隆过滤器 2、布隆过滤器的原理 2.1 布隆过滤器的数据结构 2.2 布隆过滤器的检索和插入原理 2.3 布隆过滤器元素的修改和删除 3、布隆过滤器的使用场景 3.1 Redis通过布隆过滤器防止缓存穿透 3.2 RocketMQ通过布隆过滤器防止消息重复消费 4、布隆过滤器…

DAPP开发(三)——智能合约开发

智能合约 Remix IDE 是开发以太坊智能合约的在线IDE工具&#xff0c;部署简单的智能合约非常方便。 http://remix.ethereum.org truffle 一个世界级的智能合约开发框架&#xff0c;专为智能合约而生。 管理智能合约的生命周期自动化合约测试可编程&#xff0c;可部署&…