当前位置: 首页 > news >正文

【QT5】<应用> 小游戏:贪吃蛇

文章目录

一、项目要求

二、需求分析

三、实现效果

四、代码


一、项目要求

【1】主要实现:游戏界面存在一条蛇🐍,使用键盘wsad或者↑↓←→键盘可以控制蛇的行走方向。同时界面中会随机出现食物,蛇可以吃食物,然后蛇的身体就会变长。吃完一个食物之后才会刷新另外一个食物。

【2】游戏结束:蛇碰壁。

【3】玩家分数:由蛇的存活时间以及长度综合计算。time为蛇存活的秒数,lent-len0表示蛇增加的节点数量。同时,玩家分数需要实时显示

【4】重新开始:点击相应的按钮。

【5】加速模式:双击键盘可以加速蛇的移动。例如按两下w键,蛇的速度变为原来的2倍。

【6】不同食物:食物有多种类别,不同的食物会导致蛇变长的长度不同。


二、需求分析

【1】针对主要实现:

  • 创建蛇(Snake)食物(Food)主要窗口(Widget)类。
  • Snake类:创建方法来实现蛇的移动(头插一个,尾删一个)、蛇的方向检测(根据键盘值)、蛇是否死亡(是否碰壁)以及在窗口中绘制蛇(通过传入painter)。
  • Food类:创建方法来实现食物的坐标生成和类型生成(利用随机数)、在窗口中绘制食物。用type整型变量来标志食物类型,当type=1时蛇吃掉后加1节,当type=2时蛇吃掉后加2节,以此类推。
  • Widget类:创建方法来实现整体的按键检测绘制图像计算玩家分数。为了让蛇不断移动,使用定时器(QTimer)来周期性触发槽函数,在槽函数中执行蛇吃食物、食物更新、画面更新等操作。
  • 按键控制:①↑↓←→键盘控制蛇的移动;②空格键控制游戏的开始/暂停(控制定时器开始/停止)。
  • 综合不同类的绘图:将主要逻辑的Widget类中实例化的painter对象作为形参传入Snake和Food类中,在它们各自的方法中进行各自的绘图操作。

【2】针对重新开始:

  • 在ui设计器中添加QPushButton,并添加相应的槽函数。
  • 槽函数中将分数、暂停标志、时间计数器等属性恢复初始值。
  • 槽函数中将已有的蛇、食物对象delete,再创建新的蛇、食物对象。
  • 槽函数中需要重新聚焦于gameWidget,否则点击按钮后需要再点击gameWidget才能检测键盘的输入。重新聚焦调用"ui->gameWidget->setFocus();"

【3】针对不同速度:

  • 在Snake类中创建属性speed,当speed为1时表示每次触发定时器槽函数执行蛇前进1格,当speed为2时表示每次触发定时器槽函数执行蛇前进2格。
  • 初始化speed为1,当用户手动按下两下↑后会加速,直到用户改变蛇的方向

【4】针对不同食物:

  • 在Food类中创建属性type,当type为1时表示食物类型为1(蛇吃后增加1节),当type为2时表示食物类型为2(蛇吃后增加2节),当type为3时表示食物类型为3(蛇吃后增加3节)。
  • 类型1设定为绿色的圆形
  • 类型2设定为深蓝色的椭圆
  • 类型3设定为浅蓝色的方形

三、实现效果


四、代码

【1】food.h:

#ifndef FOOD_H
#define FOOD_H#include <QWidget>
#include <QPainter>
#include <QRandomGenerator>/************************************************************ @类名:	Food* @摘要:	食物类* @作者:	柯同学* @注意:	三种食物类型:type值为几就加几节蛇身*********************************************************/
class Food : public QWidget
{Q_OBJECT
public:explicit Food(QWidget *parent = nullptr);int getX();         //返回食物横坐标int getY();         //返回食物纵坐标int getRadius();    //返回食物半径int getType();      //返回食物类型void generateFood();//生成食物的坐标和类型void paintFood(QPainter &painter);//绘制食物private:int foodX;  //食物横坐标int foodY;  //食物纵坐标int radius; //食物半径int type;   //食物类型:1类型为增加1节,2类型增加2节,3类型增加3节
};#endif // FOOD_H

【2】food.cpp:

#include "food.h"/************************************************************ @函数名:Food* @功  能:食物类的构造函数* @参  数:parent父对象* @返回值:无*********************************************************/
Food::Food(QWidget *parent): QWidget(parent), radius(15)
{//初始的食物也随机generateFood();
}/************************************************************ @函数名:getX* @功  能:返回食物的横坐标* @参  数:无* @返回值:食物的横坐标*********************************************************/
int Food::getX()
{return foodX;
}/************************************************************ @函数名:getY* @功  能:返回食物的纵坐标* @参  数:无* @返回值:食物的纵坐标*********************************************************/
int Food::getY()
{return foodY;
}/************************************************************ @函数名:getRadius* @功  能:返回食物的半径* @参  数:无* @返回值:食物的半径*********************************************************/
int Food::getRadius()
{return radius;
}/************************************************************ @函数名:getType* @功  能:返回食物的类型* @参  数:无* @返回值:食物的类型*********************************************************/
int Food::getType()
{return type;
}/************************************************************ @函数名:generateFood* @功  能:随机生成食物的坐标、类型* @参  数:无* @返回值:无*********************************************************/
void Food::generateFood()
{//随机生成坐标,距边界radius降低反应难度foodX = QRandomGenerator::global()->bounded(10 + radius, 580 - radius * 2);foodY = QRandomGenerator::global()->bounded(20 + radius, 570 - radius * 2);//随机生成类型[1,4)type = QRandomGenerator::global()->bounded(1, 4);
}/************************************************************ @函数名:paintFood* @功  能:根据食物类型的不同,绘制不同的食物类型。* @参  数:painter---画家对象* @返回值:无* @说  明:type=1---类型1:绿色的圆形*         type=2---类型2:深蓝色的椭圆形*         type=3---类型3:淡蓝色的矩形*********************************************************/
void Food::paintFood(QPainter &painter)
{QPen pen;QBrush brush;//根据type不同,绘制不同的食物switch (this->type){case 1:pen.setColor(QColor(43, 220, 112));brush.setColor(QColor(43, 220, 112));brush.setStyle(Qt::SolidPattern);painter.setPen(pen);painter.setBrush(brush);painter.drawEllipse(QRect(foodX, foodY, radius, radius));break;case 2:pen.setColor(QColor(0, 62, 146));brush.setColor(QColor(0, 62, 146));brush.setStyle(Qt::SolidPattern);painter.setPen(pen);painter.setBrush(brush);painter.drawEllipse(QRect(foodX, foodY, radius*2, radius));break;case 3:pen.setColor(QColor(29, 130, 154));brush.setColor(QColor(29, 130, 154));brush.setStyle(Qt::SolidPattern);painter.setPen(pen);painter.setBrush(brush);painter.drawRect(QRect(foodX, foodY, radius, radius));break;}
}

【3】snake.h:

#ifndef SNAKE_H
#define SNAKE_H#include <QWidget>
#include <QEvent>
#include <QPaintEvent>
#include <QPainter>//枚举蛇前进的方向
enum Direct{MOVE_UP,MOVE_DOWN,MOVE_LEFT,MOVE_RIGHT
};/************************************************************ @类名:	Snake* @摘要:	蛇类* @作者:	柯同学* @注意:	有两种速度:speed为1就每次timeout前进1格,以此类推。*         在原有方向的基础上,再次按原方向键能切换到二倍速模式,*         比如蛇在往上,再次按up键就两倍速,直到切换方向。*********************************************************/
class Snake : public QWidget
{Q_OBJECT
public:explicit Snake(QWidget *parent = nullptr);void paintSnake(QPainter &painter); //绘制蛇身void keyPress(QKeyEvent *event);    //键盘控制移动方向void autoMove();        //沿着方向自动移动void frontAddBody();     //根据方向增加首节点QRect getSnakeHead();   //获取蛇的首节点信息int getLength();        //返回蛇身节点个数bool isOver();          //返回蛇是否死亡,死亡为trueprivate:QList<QRect> body;  //蛇身int nodeWidth;      //节点宽度int nodeHeight;     //节点高度int moveDirect;     //移动方向int speed;          //移动速度:1表示默认速度,2表示两倍速度
};#endif // SNAKE_H

【4】snake.cpp:

#include "snake.h"/************************************************************ @函数名:Snake* @功  能:蛇的构造函数* @参  数:parent---父对象* @返回值:无* @说  明:初始化三节蛇身*********************************************************/
Snake::Snake(QWidget *parent): QWidget(parent), nodeWidth(20), nodeHeight(20), moveDirect(MOVE_LEFT), speed(1)
{//初始给定三节蛇身body.append(QRect(400, 300, nodeWidth, nodeHeight));body.append(QRect(400 + nodeWidth, 300, nodeWidth, nodeHeight));body.append(QRect(400 + nodeWidth * 2, 300, nodeWidth, nodeHeight));
}/************************************************************ @函数名:getLength* @功  能:获取蛇身的长度,即有几个节点* @参  数:无* @返回值:蛇身的长度*********************************************************/
int Snake::getLength()
{return body.length();
}/************************************************************ @函数名:isOver* @功  能:判定蛇是否碰墙死亡* @参  数:无* @返回值:true---蛇死亡,false---蛇没有死亡*********************************************************/
bool Snake::isOver()
{if (body[0].y() <= 20 || body[0].y() + nodeHeight >= 570 ||body[0].x() <= 10 || body[0].x() + nodeWidth >= 580) {return true;}return false;
}/************************************************************ @函数名:keyPress* @功  能:按键检测,控制蛇的前进方向* @参  数:event---按键的事件* @返回值:无* @说  明:在原有方向的基础上,再次按原方向键能切换到二倍速模式*********************************************************/
void Snake::keyPress(QKeyEvent *event)
{switch(event->key()) {case Qt::Key_Up://蛇往上if (MOVE_UP == moveDirect){speed = 2;}else if (moveDirect != MOVE_DOWN){moveDirect = MOVE_UP;speed = 1;}break;case Qt::Key_Down://蛇往下if (MOVE_DOWN == moveDirect){speed = 2;}else if (moveDirect != MOVE_UP){moveDirect = MOVE_DOWN;speed = 1;}break;case Qt::Key_Left://蛇往左if (MOVE_LEFT == moveDirect){speed = 2;}else if (moveDirect != MOVE_RIGHT){moveDirect = MOVE_LEFT;speed = 1;}break;case Qt::Key_Right://蛇往右if (MOVE_RIGHT == moveDirect){speed = 2;}else if (moveDirect != MOVE_LEFT){moveDirect = MOVE_RIGHT;speed = 1;}break;default:break;}
}/************************************************************ @函数名:autoMove* @功  能:根据speed属性,让蛇前进1格或2格* @参  数:无* @返回值:无* @说  明:蛇的前进做法:每次头插一个节点,删除最后的一个节点*********************************************************/
void Snake::autoMove()
{if (1 == speed){frontAddBody();body.removeLast();}else if (2 == speed){frontAddBody();frontAddBody();body.removeLast();body.removeLast();}
}/************************************************************ @函数名:frontAddBody* @功  能:根据前进方向,头插不同位置的节点* @参  数:无* @返回值:无* @说  明:由于碰壁就死亡了,无需越界判定*********************************************************/
void Snake::frontAddBody()
{switch (moveDirect){case MOVE_UP:body.insert(0, QRect(body[0].x(), body[0].y() - nodeHeight, nodeWidth, nodeHeight));break;case MOVE_DOWN:body.insert(0, QRect(body[0].x(), body[0].y() + nodeHeight, nodeWidth, nodeHeight));break;case MOVE_LEFT:body.insert(0, QRect(body[0].x() - nodeWidth, body[0].y(), nodeWidth, nodeHeight));break;case MOVE_RIGHT:body.insert(0, QRect(body[0].x() + nodeWidth, body[0].y(), nodeWidth, nodeHeight));break;}
}/************************************************************ @函数名:getSnakeHead* @功  能:返回首节点的拷贝,以防外界修改。* @参  数:无* @返回值:无*********************************************************/
QRect Snake::getSnakeHead()
{return body[0];
}/************************************************************ @函数名:paintSnake* @功  能:绘制蛇身,遍历QList* @参  数:painter---画家对象* @返回值:无*********************************************************/
void Snake::paintSnake(QPainter &painter)
{//设置painterQPen pen(QColor(64, 65, 66));QBrush brush(QColor(183, 1, 1));painter.setPen(pen);painter.setBrush(brush);//绘制蛇身for (int i = 0; i < body.length(); ++i) {painter.drawRect(body[i]);}
}

【5】widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "snake.h"
#include "food.h"
#include <QPainter>
#include <QTimer>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE/************************************************************ @类名:	Widget* @摘要:	主要界面类* @作者:	柯同学* @注意:	在该类中进行蛇吃食物、游戏结束等逻辑的实现*********************************************************/
class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void paintEvent(QPaintEvent *event) override;   //绘图void keyPressEvent(QKeyEvent *event) override;  //按键检测void snakeEatFood();    //蛇吃食物,更新食物void computeScore();    //计算玩家分数private slots:void timeOut();         //定时器触发的槽函数void on_pushButton_clicked();//"重新开始"按钮的槽函数private:Ui::Widget *ui;Snake *snake;   //蛇Food *food;     //食物QTimer *timer;  //定时器,固定100ms触发bool isPause;   //开始或暂停的标志,true为暂停int timerCount; //定时器触发次数double score;   //玩家分数
};
#endif // WIDGET_H

【6】widget.cpp:

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>/************************************************************ @函数名:Widget* @功  能:主要窗口的构造函数* @参  数:parent---父对象* @返回值:无*********************************************************/
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), isPause(true), timerCount(0), score(0)
{ui->setupUi(this);//实例化蛇snake = new Snake(ui->gameWidget);//实例化食物food = new Food(ui->gameWidget);//设置定时器timer = new QTimer(this);connect(timer, SIGNAL(timeout()), this, SLOT(timeOut()));//设置聚焦对象ui->gameWidget->setFocus();
}/************************************************************ @函数名:~Widget* @功  能:主要窗口的析构函数* @参  数:无* @返回值:无* @说  明:由于QT的对象树机制,绑定好父对象后无需手动delete其他空间*********************************************************/
Widget::~Widget()
{delete ui;
}/************************************************************ @函数名:~Widget* @功  能:主要窗口的析构函数* @参  数:无* @返回值:无*********************************************************/
void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event)QPainter painter(this);//判定游戏是否结束,结束则显示提示if (snake->isOver()) {//蛇死亡,游戏结束timer->stop();isPause = true;QFont font("宋体", 30, QFont::ExtraBold,false);painter.setFont(font);QRect showArea(200, 250, 200, 100);painter.drawText(showArea, Qt::AlignHCenter | Qt::AlignVCenter, "游戏结束!");}//绘制蛇和食物snake->paintSnake(painter);food->paintFood(painter);//实时显示玩家分数ui->scoreLabel->setText("分数: " + QString::number(score));
}/************************************************************ @函数名:keyPressEvent* @功  能:重写的按键检测事件函数* @参  数:event---按键事件* @返回值:无* @说  明:以防游戏结束后还能控制,首先需要判定游戏是否结束*********************************************************/
void Widget::keyPressEvent(QKeyEvent *event)
{//游戏未结束才进行按键控制if (!(snake->isOver())) {//按键控制蛇移动snake->keyPress(event);//按键控制暂停if (event->key() == Qt::Key_Space) {if (isPause){isPause = false;timer->start(100);}else {isPause = true;timer->stop();}}}
}/************************************************************ @函数名:snakeEatFood* @功  能:蛇与食物接触,则给蛇加节点,给食物重新生成坐标和类型* @参  数:无* @返回值:无* @说  明:生成食物必须放在蛇加节点之后*********************************************************/
void Widget::snakeEatFood()
{//蛇与食物接触if (abs(snake->getSnakeHead().x() - food->getX()) <= food->getRadius() &&abs(snake->getSnakeHead().y() - food->getY()) <= food->getRadius()){//蛇吃不同类型食物加不同节int count = food->getType();while (count--){snake->frontAddBody();}//再次生成食物food->generateFood();}
}/************************************************************ @函数名:computeScore* @功  能:计算玩家分数* @参  数:无* @返回值:无* @说  明:分数由两部分构成:时间分数、长度分数。*         每坚持1秒,分数增加1分。*         每多一节身体,分数增加10分。*********************************************************/
void Widget::computeScore()
{double timeScore = (timerCount / 10.0) * 1;     //时间的分数,每秒1分int lenScore = (snake->getLength() - 3) * 10;   //长度的分数,增一节10分if (lenScore >= 0)this->score = timeScore + lenScore;
}/************************************************************ @函数名:timeOut* @功  能:定时器的槽函数* @参  数:无* @返回值:无*********************************************************/
void Widget::timeOut()
{//蛇自动移动,吃食物snake->autoMove();snakeEatFood();//计算玩家分数timerCount++;computeScore();//更新界面this->update();
}/****************************************************************** @函数名:on_pushButton_clicked* @功  能:"重新开始"按钮的槽函数* @参  数:无* @返回值:无* @说  明:需要重新聚焦于gameWidget,否则点击按钮后需要再点击gameWidget***************************************************************/
void Widget::on_pushButton_clicked()
{//清除相关属性timerCount = 0; //定时器计数清零score = 0;      //分数清零isPause = true; //恢复暂停//删除已有成员对象if (snake) {delete snake;}if (food) {delete food;}//创建新对象snake = new Snake(ui->gameWidget);food = new Food(ui->gameWidget);//更新界面this->update();ui->gameWidget->setFocus();//重新聚焦于游戏窗口
}

【7】main.cpp: 系统自动生成的,没有改动。

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

相关文章:

【QT5】<应用> 小游戏:贪吃蛇

文章目录 一、项目要求 二、需求分析 三、实现效果 四、代码 一、项目要求 【1】主要实现&#xff1a;游戏界面存在一条蛇&#x1f40d;&#xff0c;使用键盘wsad或者↑↓←→键盘可以控制蛇的行走方向。同时界面中会随机出现食物&#xff0c;蛇可以吃食物&#xff0c;然后…...

【Webpack】使用 Webpack 构建 Vue3+TS 项目

构建项目目录 tsc --init npm init -yshim.d.ts 文件是一个类型声明文件&#xff0c;用于告诉 TypeScript 编译器如何处理 Vue 的单文件组件&#xff08;SFC&#xff09;和其他自定义模块。为 Vue 的单文件组件和其他非 TypeScript 模块提供类型信息&#xff0c;以便在 TypeScr…...

数据防泄漏的六个步骤|数据防泄漏软件有哪些

在当前复杂多变的网络安全环境下&#xff0c;数据防泄漏软件成为了企业信息安全架构中不可或缺的一环。下面以安企神软件为例&#xff0c;告诉你怎么防止数据泄露&#xff0c;以及好用的防泄露软件。 1. 安企神软件 安企神软件是当前市场上备受推崇的企业级数据防泄漏解决方案…...

SpringCloud 网关Gateway配置并使用

目录 1 什么是网关&#xff1f; 2 Gateway的使用 2.1 在其pom文件中引入依赖 2.2 然后gateway配置文件中配置信息 2.3 启动网关微服务 3 网关处理流程 4 前端-网关-微服务-微服务间实现信息共享传递 1 什么是网关&#xff1f; 网关&#xff1a;就是网络的关口&#xff…...

MySQl基础----Linux下搭建mysql软件及登录和基本使用(附实操图超简单一看就会)

绪论​ 涓滴之水可磨损大石&#xff0c;不是由于他力量强大&#xff0c;而是由于昼夜不舍地滴坠。 只有勤奋不懈地努力&#xff0c;才能够获得那些技巧。 ——贝多芬。新开MySQL篇章&#xff0c;本章非常基础包括如何在Linux上搭建&#xff08;当然上面的SQL语句你在其他能执行…...

PostgreSQL17优化器改进(4)允许UNION(没有ALL)使用MergeAppend

PostgreSQL17优化器改进(4)允许UNION(没有ALL)使用MergeAppend UNION存在的问题 到PostgreSQL16.3版本为止&#xff0c;UNION执行计划通常不是最优的&#xff0c;优化器有两种处理方法&#xff1a; 优化器只考虑使用Append节点并通过使用Hash Aggregate&#xff0c;Append -…...

SSM 基于大数据技术的创业推荐系统-计算机毕业设计源码02979

摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。在现实运用中&#xff0c;应用软件的工作…...

基于WPF技术的换热站智能监控系统03--实现左侧加载动画

1、左侧布局规划 左侧分5行&#xff0c;每行的高度通过height属性来指定&#xff0c;1.2*表示占1.2倍的宽度 2、创建用户控件 在WPF中想要进行个性化处理&#xff0c;主要可以通过三个方面来实现&#xff1a;控件模板&#xff08;控件模板、数据模板、数据容器模板&#xff09…...

4D毫米波雷达技术及发展

文章目录 前言一、4D毫米波雷达是什么&#xff1f;二、毫米波雷达是什么&#xff1f;毫米波雷达的基本原理多普勒效应 前言 现阶段自动驾驶技术中&#xff0c;主要用到的传感器有摄像头、激光雷达和毫米波雷达。 摄像头的光谱从可见光到红外光谱&#xff0c;是最接近人眼的传感…...

请解释Java Web应用的开发流程,包括前后端分离和交互方式。请解释Java中的锁分离技术,并讨论其在提高并发性能方面的作用。

请解释Java Web应用的开发流程&#xff0c;包括前后端分离和交互方式。 Java Web应用的开发流程是一个涵盖多个阶段的过程&#xff0c;这些阶段从需求分析开始&#xff0c;经过设计、编码、测试&#xff0c;最终到部署和维护。在这个过程中&#xff0c;前后端分离成为现代Web应…...

selenium使用已经打开的浏览器

Selenium 本身不支持直接连接到一个已经打开的浏览器页面。Selenium 启动的浏览器实例是一个全新的会话&#xff0c;它与手动打开的浏览器页面是分开的。但是&#xff0c;有一些变通的方法可以实现类似的效果。 一种方法是通过附加代理连接到已经打开的浏览器。下面是如何实现…...

Redis: 深入解析高性能内存数据库的实现原理

一、Redis简介 Redis是一种基于内存的键值存储数据库&#xff0c;支持丰富的数据类型&#xff0c;如字符串、列表、集合、有序集合和哈希表。它不仅具有极高的性能&#xff0c;还支持数据持久化、主从复制和分布式架构&#xff0c;使其在各种应用场景中表现出色。 1.1 Redis的…...

使用 Python进行自动备份文件

文件备份对数据保护至关重要&#xff0c;让我们使用 shutil 模块创建一个简单的备份脚本 这段代码的作用就是将指定源目录中的所有文件备份到目标备份目录中&#xff0c;并在备份目录中创建带有时间戳的子目录&#xff0c;通过定期运行这段代码&#xff0c;可以实现自动备份文…...

02_01_SpringMVC初识

一、回顾MVC三层架构 1、什么是MVC三层 MVC是 模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;、控制器&#xff08;Controller&#xff09;的简写&#xff0c;是一种软件设计规范。主要作用是降低视图与业务逻辑之间的双向耦合&#xff0c;它不是一种…...

Python学习打卡:day04

day4 笔记来源于&#xff1a;黑马程序员python教程&#xff0c;8天python从入门到精通&#xff0c;学python看这套就够了 目录 day428、while 循环的嵌套应用29、while 循环案例 — 九九乘法表补充知识示例&#xff1a;九九乘法表 30、for 循环基本语法while 和 for 循环对比f…...

gitlab问题记录

You wont be able to pull or push project code via SSH until you add an SSH key to you 解决方案&#xff1a;https://blog.csdn.net/gufenchen/article/details/95663284...

OpenCV练习(1)签名修复

1.目的 在学校的学习过程中&#xff0c;需要递交许多材料&#xff0c;且每份材料上都需要对应负责人签名&#xff0c;有时候找别人要签名&#xff0c;然后自己粘贴的话&#xff0c;会出现签名模糊&#xff0c;背景不是纯白透明。为此以word中的“颜色校正”功能为参照&#xf…...

软设之系统测试之测试的基本概念及分类

测试的基本概念 尽早&#xff0c;不断地进行测试 程序员避免测试自己设计的程序 既要选择有效&#xff0c;合理的数据&#xff0c;也要选择无效&#xff0c;不合理的数据 修改后应进行回归测试 尚未发现的错误数量与该程序已发现错误其他成正比。 动态测试 黑盒测试(测试…...

Python学习打卡:day06

day6 笔记来源于&#xff1a;黑马程序员python教程&#xff0c;8天python从入门到精通&#xff0c;学python看这套就够了 目录 day648、函数综合案例49、数据容器入门50、列表的定义语法51、列表的下标索引1、列表的下标&#xff08;索引&#xff09;2、列表的下标&#xff08…...

支付宝 沙盒demo使用

简介&#xff1a;支付宝沙箱环境是一个为开发者提供的模拟测试环境&#xff0c;用于在应用上线前进行接口功能开发和联调。在这个环境中&#xff0c;开发者可以模拟开放接口&#xff0c;进行开发调试工作&#xff0c;以确保应用上线后能顺利运行。 1. 配置沙盒 1. 1 沙箱控制…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

AD学习(3)

1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分&#xff1a; &#xff08;1&#xff09;PCB焊盘&#xff1a;表层的铜 &#xff0c;top层的铜 &#xff08;2&#xff09;管脚序号&#xff1a;用来关联原理图中的管脚的序号&#xff0c;原理图的序号需要和PCB封装一一…...

2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案

一、延迟敏感行业面临的DDoS攻击新挑战 2025年&#xff0c;金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征&#xff1a; AI驱动的自适应攻击&#xff1a;攻击流量模拟真实用户行为&#xff0c;差异率低至0.5%&#xff0c;传统规则引…...