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

【C语言】简单贪吃蛇实现保姆级教学!!!

在这里插入图片描述关注小庄 顿顿解馋૮(˶ᵔ ᵕ ᵔ˶)ა 新年快乐呀小伙伴

引言: 小伙伴们应该都有一个做游戏的梦吧?今天让小庄来用C语言简单实现一下我们的童年邪典贪吃蛇,顺便巩固我们的C语言知识,请安心食用~

文章目录

  • 贪吃蛇效果
  • 一.游戏前工作
    • 🏠 控制台程序
    • 🏠 光标设置
      • 📌 Win32API
    • 🏠 绘制地图
      • 📌 控制台坐标系
      • 📌 控制台坐标的设置
      • 📌 墙壁图案
    • 🏠 帮助信息
    • 🏠 贪吃蛇整体维护
      • 📌蛇的初始化
      • 📌食物创建
      • 📌其他内容初始化
  • 二.游戏运行时工作
    • 🏠 游戏逻辑
    • 🏠 按键检测
    • 🏠 蛇的移动
      • 📌蛇是否吃到食物
      • 📌蛇是否撞墙和咬到自身
  • 三.游戏善后工作
    • 🏠 贪吃蛇资源的释放
    • 🏠 贪吃蛇游戏状态
    • 🏠 拓展

贪吃蛇效果

如下是我们将实现的效果 请看vcr

一.游戏前工作

🏠 控制台程序

平时我们运行程序弹出的黑框框就是控制台程序我们平时可能不在意它的字体颜色,大小等等…我们可以根据我们的游戏进行一些调整

  • 控制台程序标题

sysytem("title 贪吃蛇"); //包含头文件window.h

我们可以根据自己的需要修改标题

  • 控制台程序宽度和高度

ssystem("mode con cols=xxx lines=xxx"); //cols是列长 lines是行长

我们可以根据需求自行调整游戏总界面面长宽


🏠 光标设置

在这里插入图片描述

在我们游戏运行时这个光标一直浮动着不太好,我们有什么办法可以隐藏呢?当然可以这里就要介绍我们的Win32API了~

📌 Win32API

什么是API?

我们发现应用程序会有开启视窗、描绘图形、使⽤周边设备等操作,那这是怎么实现的呢 ? 那就是通过我们操作系统应用程序编程接口(Application Programming Interface),这个接口的服务对象是我们的应用程序.不同的API函数能实现不同的操作.

应用程序接口的提供者是运行库,什么样的运行库提供什么样的API,比如Linux下的Glibc库提供POSIX API;Windows的运行库提供Windows API,最常见的32位Windows提供的API又被称为Win32API

  • GetStdHandle
    GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备(标准输⼊、标准输出或标准错误)中取得⼀个句柄(⽤来标识不同设备的数值),使⽤这个句柄可以操作设备。
HANDLE GetStdHandle(DWORD nStdHandle);//参数是标准设备
参数取值含义
STD_INPUT_HANDLE标准输入设备
STD_OUTPUT_HANDLE标准输出设备
STD_ERROR_HANDLE标准错误设备

理解:不同设备可以理解为不同的门,不同门对应不同的锁,而我们的句柄相当于打开门的钥匙,有了钥匙才能破门而入探索新世界~

  • CONSOLE_CURSOR_INFO
typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;

这是一个结构体类型,用于存储控制台光标相关信息

dwSize : 由光标填充的字符单元格的百分⽐光标外观会变化,范围从完全填充单元格到单元底部的⽔平线条,该值范围为0-100超出范围不会报错但不发生变化.

bBisible : 光标的可见性.true为可见,false为不可见.

  • GetConsoleCursorInfo
    这也是个API函数用于检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息.
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
//第一个参数是我们获得的设备句柄,有了句柄才能操作设备;
//第二个参数是_CONSOLE_CURSOR_INFO结构体,我们获得将获得的光标信息放进这个结构体变量里
  • SetConsoleCursorInfo
    设置指定控制台屏幕缓冲区的光标的⼤⼩和可⻅性。存完光标信息我们就能重新设置光标信息了.
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//获取句柄
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态

了解这几个API之后我们就能设置我们的光标了~


🏠 绘制地图

我们的地图大致是这样子
在这里插入图片描述

我们知道这里我们就得普及一下控制台程序的坐标系了

📌 控制台坐标系

我们的坐标系向右是x轴,从左向右增长;坐标系向下是y轴,从上至下增长
在这里插入图片描述

📌 控制台坐标的设置

知道了坐标系后,我们得清楚我们打印东西是得看这个光标的,从光标的位置开始打印.所以我们得知道相关知识实现"定向射靶".

  • 控制台屏幕上的坐标COORD

COORD是WindowsAPI中定义的⼀个结构体,表示⼀个字符在控制台屏幕上的坐标.

  • SetConsoleCursorPosition

设置指定控制台屏幕缓冲区中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调⽤SetConsoleCursorPosition函数将光标位置设置到指定的位置.

//设置光标的坐标
void SetPos(short x, short y)
{
COORD pos = { x, y };
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos
SetConsoleCursorPosition(hOutput, pos);
}

封装成一个函数这样我们就很方便的定向打靶了

📌 墙壁图案

我们地图墙的边界都是由一个个◻组成的,包括我们的蛇身也是由一个个特殊符号组成的,这些符号能直接被打印出来吗?答案是不行,原因是这些宽字符占两个字节我们的char只占一个字节满足不了我们的需求,所以我们需要用wchar_t 和宽字符的输⼊和输出函数以及本地化来进行字符打印

  • <locale.h>本地化
    由于世界文化各有不同,不同地区采用的语言也有所不同,这时我们用C语言输出字符就会出现地区差异,而我们的locale.h头文件提供的函数就很好地为我们解决了这个问题

  • setlocale函数

char* setlocale (int category, const char* locale);

setlocale函数⽤于修改当前地区,可以针对⼀个类项修改,也可以针对所有类项,以下是部分类项

类项代表意义
LC_ALL所有类别
LC_TIMEstrftime 和 wcsftime 函数
LC_CTYPE字符处理函数
LC_MONETARYlocaleconv 函数返回的货币格式信息

第二个参数只有两个取值

1.“” 表示切换到本地模式,此时可以用本地的字符集等

  • “C” 表示默认的正常方式

本地化后我们就能打印本地区的一些宽字符了

  • 宽字符打印
int main()
{setlocale(LC_ALL, "");wchar_t ch1 = L'中';wchar_t ch2 = L'国';wchar_t ch3 = L'★';wchar_t ch4 = L'●';wprintf(L"%lc\n", ch1);wprintf(L"%lc\n", ch2);wprintf(L"%lc\n", ch3);wprintf(L"%lc\n", ch4);printf("ab\n");return 0;
}

注意: 宽字符类型前面要加一个L表示宽字符,打印输出用wprintf接收wchar_t类型变量,打印格式为L%lc

明白这些后我们就能绘制地图了,代码如下

void Createmap()
{//上  从(0,0)开始宽字符是普通字符的两倍 不断加2Setpos(0, 0);for (int i = 0; i <= 56; i += 2){wprintf(L"%lc", WALL);}//下Setpos(0, 25);for (int i = 0; i <= 56; i += 2){wprintf(L"%lc", WALL);}//左for (int i = 1; i <= 25; i++){Setpos(0,i);wprintf(L"%lc", WALL);}//右for (int i = 1; i <= 25; i++){Setpos(56, i);wprintf(L"%lc", WALL);}
}

🏠 帮助信息

我们可以在加载游戏地图前提供开始界面和帮助信息,注意设置好光标的位置,代码如下

void Welcomeinfo()
{Setpos(37, 13);printf("欢迎来到贪吃蛇小游戏ovo");Setpos(37, 22);system("pause");Setpos(33, 13);printf("用↑ ↓ ← →移动 shift来加速 ctrl来减速");Setpos(37, 22);system("pause");system("cls");
}

大致效果如下
在这里插入图片描述


🏠 贪吃蛇整体维护

对于贪吃蛇的整体游戏我们有蛇睡眠时间,贪吃蛇这条蛇本身,游戏分数,食物权重等等信息,这时我们可以想到用我们的结构体来储存我们的信息,同时我们蛇可以看作是链表构成,里面存储坐标以及next指针

//游戏状态
enum Status
{OK = 1,ESC,//正常退出KILL_BYWALL,//撞墙KILL_BYSELF//自己咬到自己
};
//蛇运动的方向
enum Die
{UP=1,DOWN,LEFT,RIGHT
};//定义蛇身结点typedef int Datatype;
typedef struct SnakeNode
{//储存坐标int x;int y;struct SnakeNode* next;
}SnakeNode,* pSnakeNode;//定义整个贪吃蛇要维护的内容
typedef struct Snake
{pSnakeNode snake;//蛇pSnakeNode pFood;//食物int Score;//当前分数int FoodWeight;//每个食物的权重int sleeptime;//睡眠时间enum Status status;//游戏状态enum Dir dir;//蛇运动方向}Snake,* pSnake;

📌蛇的初始化

对于蛇的初始化我们可以以链表的形式运用尾插链接蛇,值得注意的是蛇的坐标要设置成2的倍数,不然蛇蛇一半身体会卡到墙里,在创建蛇的结点的同时打印蛇身

#define BODY L'●'
#define POS_X 24
#define POS_Y 5
//初始化蛇
void InitSnake(pSnake ps)
{//创建蛇 五个结点pSnakeNode newhead = NULL;pSnakeNode newtail = NULL;for (int i = 0; i < 5; i++){//创建新结点并初始化化他们的坐标pSnakeNode cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("malloc failed");exit(1);}cur->x = POS_X + 2*i;//这里要这个两倍不然会发生覆盖cur->y = POS_Y;cur->next = NULL;Setpos(cur->x,cur->y);wprintf(L"%lc", BODY);//链表为空新结点作为头结点if (newhead == NULL){newtail = newhead = cur;}else{///头插cur->next = ps->snake;ps->snake = cur;}}//其他内容的初始化ps->sleeptime = 200;ps->Score = 0;ps->FoodWeight = 10;ps->status = OK;ps->dir = UP;ps->pFood = NULL;
}

📌食物创建

对于食物我们也可以看成链表的一个结点但有几点需要注意:

  1. 食物的坐标要是随机 可以用rand函数解决
  2. 食物的坐标不能与墙壁重叠且食物坐标也要是二的倍数保证不卡墙
  3. 食物坐标不能与蛇身重叠 可以遍历链表进行比较不满足重新生成
void CreateFood(pSnake ps)
{//先产生坐标 int x = 0;int y = 0;//横坐标要是偶数again:do{x = rand() % 53 + 2;	//2-54 --> 0~52+2y = rand() % 24 + 1 ;   //1~24} while (x%2!=0);//不能超出墙 同时不能跟这个蛇的坐标重叠pSnakeNode cur = ps->snake;while (cur){if (x == cur->x &&y == cur->y){goto again;//与蛇重叠重新产生}cur = cur->next;}pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));if (pFood == NULL){perror("CreateFood()::malloc()");return;}pFood->x = x;pFood->y = y;ps->pFood = pFood;Setpos(x,y);wprintf(L"%lc", FOOD);
}

📌其他内容初始化

除了蛇之外我们还有游戏状态,蛇睡眠时间以及分数等等

ps->snake = newtail;//其他内容的初始化ps->sleeptime = 200;ps->Score = 0;ps->FoodWeight = 10;ps->status = OK;ps->dir = UP;ps->pFood = NULL;

二.游戏运行时工作

🏠 游戏逻辑

准备好前置工作后我们就可以着手准备我们的游戏运行工作了,首先我们需要确定游戏的大体逻辑

大体逻辑:玩家根据游戏提示按键—>根据按键判断下步该做什么工作 : 在状态OK下实现蛇的移动 pause状态则是暂停 ESC状态是正常退出 也就是说状态不是OK就是退出程序(一个循环)


🏠 按键检测

我们在C语言中怎么检测我们的按键情况呢?这要请出我们一个新的API函数GetAsyncKeyState

  • GetAsyncKeyState
SHORT GetAsyncKeyState
(int vKey
);
//将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态

返回值:返回的16位的short数据中,最⾼位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态抬起;如果最低位被置为1则说明,该按键被按过,否则为0。

所以我们可以通过检测函数返回值的最低位是否为1来检测按键情况,可以用一个宏封装

#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )

基于这个API函数和我们的游戏逻辑就能实现我们游戏运行基本的代码

void pause(pSnake ps)
{while (1){if (KEY_PRESS(VK_SPACE)){return;}}
}void GameRun(pSnake ps)
{//帮助信息Helpinfo();//游戏luojido {Setpos(64, 10);printf("得分:%d ", ps->Score);printf("每个⻝物得分:%d分", ps->FoodWeight);if (KEY_PRESS(VK_UP) && ps->dir != DOWN){//保证相对方向的不冲突ps->dir = UP;}else if (KEY_PRESS(VK_DOWN) && ps->dir != UP){ps->dir = DOWN;}else if (KEY_PRESS(VK_LEFT) && ps->dir != RIGHT){ps->dir = LEFT;}else if (KEY_PRESS(VK_RIGHT) && ps->dir != LEFT){ps->dir = RIGHT;}else if (KEY_PRESS(VK_ESCAPE) && ps->dir != DOWN){//退出ps->status = ESC;}else if (KEY_PRESS(VK_SPACE) && ps->dir != DOWN){//暂停pause(ps);}else if (KEY_PRESS(VK_CONTROL) && ps->dir != DOWN){//减速if (ps->sleeptime < 350){ps->sleeptime += 30;ps->FoodWeight -= 2;if (ps->sleeptime == 350){ps->FoodWeight = 1;}}}else if (KEY_PRESS(VK_SHIFT) && ps->dir != DOWN){//加速 就是减少睡眠时间if (ps->sleeptime >= 50){ps->sleeptime -= 30;ps->FoodWeight += 2;}}//休眠Sleep(ps->sleeptime);//移动SnakeMove(ps);} while (ps->status == OK);}

注意:1.要保证按键方向不冲突 2.蛇休眠时间和食物权重不能为负数


🏠 蛇的移动

接下来就是整个游戏的运行的重头戏了

📌蛇是否吃到食物

分析:
对于我们的蛇,它吃到食物蛇长就会增加,也就是结点会增多,那么我们需要判断每次执行按键命令时我们是否会吃到食物。如果吃到食物的话我们就根据移动方向新插入一个结点同时创建新食物;如果没吃到食物我们仍然插入新结点,但尾结点打印空格再释放掉

实现代码如下

int IsFood(pSnake ps,pSnakeNode cur)
{//判断新结点是否与食物的坐标重合if (cur->x == ps->pFood->x && cur->y == ps->pFood->y)return 1;elsereturn 0;
}
void Eatfood(pSnake ps,pSnakeNode cur)
{//吃到食物直接头插cur->next = ps->snake;ps->snake = cur;pSnakeNode del = ps->snake;while (del){Setpos(del->x, del->y);wprintf(L"%lc", BODY);del = del->next;}//增加总分ps->Score += ps->FoodWeight;//释放食物free(ps->pFood);//创建新食物CreateFood(ps);
}void NotEatfood(pSnake ps, pSnakeNode cur)
{//仍然尾插cur->next = ps->snake;ps->snake = cur;//最后一个不打印pSnakeNode del = ps->snake;while (del->next->next){Setpos(del->x, del->y);wprintf(L"%lc", BODY);del = del->next;}Setpos(del->x,del->y);wprintf(L"%lc", BODY);//最后一个位置打印空格并释放Setpos(del->next->x, del->next->y);printf("  ");free(del->next);del->next = NULL;
}
//蛇的移动
void SnakeMove(pSnake ps)
{//创建 新节点pSnakeNode cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("malloc failed");exit(1);}cur->next = NULL;//根据方向确定新结点的坐标switch (ps->dir){case UP:cur->x = ps->snake->x;cur->y = ps->snake->y - 1;break;case DOWN:cur->x = ps->snake->x;cur->y = ps->snake->y + 1;break;case LEFT:cur->x = ps->snake->x - 2;cur->y = ps->snake->y;break;case RIGHT:cur->x = ps->snake->x + 2;cur->y = ps->snake->y;break;}//是否吃到食物if (IsFood(ps, cur)){//吃到食物Eatfood(ps,cur);}else{//没吃到食物NotEatfood(ps,cur);}//是否撞墙和咬到自己Kill_ByWall();Kill_BySelf()}

📌蛇是否撞墙和咬到自身

在进行上下左右移动时,我们可能会咬到自己或撞墙,这时游戏就会结束了我们需要进行游戏状态的更新

void Kill_ByWall(pSnake ps)
{pSnakeNode pcur = ps->snake;if (pcur->x == 0 || pcur->x == 56 || pcur->y == 0 || pcur->y == 26){  //蛇头坐标不能等于这个墙壁的ps->status = KILL_BYWALL;return;}return;
}
void Kill_BySelf(pSnake ps)
{//遍历链表看蛇头是不是跟蛇身每个结点的坐标相等pSnakeNode cur = ps->snake;while (cur){if (ps->snake->x == cur->x && ps->snake->y == cur->y){ps->status = KILL_BYSELF;return;}cur = cur->next;}return;
}

三.游戏善后工作

退出循环后我们需要释放游戏资源同时根据游戏状态确定提示信息

🏠 贪吃蛇资源的释放

	//释放游戏资源pSnakeNode pcur = ps->snake;while (pcur){pSnakeNode pNext = pcur->next;free(pcur);pcur = pNext;}

🏠 贪吃蛇游戏状态

//根据不同游戏状态进行提示switch (ps->status){case ESC:Setpos(12,9);printf("游戏正常退出..");Setpos(12, 10);printf("游戏总分为%d", ps->Score);break;case KILL_BYWALL:Setpos(12, 9);printf("很遗憾你撞墙了!");Setpos(12, 10);printf("游戏总分为%d", ps->Score);break;case KILL_BYSELF:Setpos(12, 9);printf("很遗憾你咬到自己了!");Setpos(12, 10);printf("游戏总分为%d", ps->Score);break;}

🏠 拓展

到这里我们基本上我们的游戏了,除此之外我们可以进行拓展,比如把三个过程函数封装进循环里实现多次游玩

void testSnake(void){int input = 0;do{Snake s;//游戏运行前GamePre(&s);//游戏运行后GameRun(&s);//游戏GameEnd(&s);Setpos(0, 28);printf("你是否想再来一把(1/0):");scanf("%d", &input);} while (input);Setpos(0, 29);
}

除此之外我们可以运用win提供的颜色API该变蛇的颜色,还有可以加入背景音乐等等…

PlaySound(MAKEINTRESOURCE(IDR_WAVE1), NULL, SND_RESOURCE | SND_ASYNC);

第一个参数:资源文件–>新建–>资源文件–>Accelerator–>导入你的.wav文件
接着打开resource.h就能找到第一个参数啦
在这里插入图片描述
最后看下效果~
在这里插入图片描述


最后到这里分享内容就结束啦,小伙伴们能学到知识的话不妨来个一键三连,祝大家2024万事顺利~

相关文章:

【C语言】简单贪吃蛇实现保姆级教学!!!

关注小庄 顿顿解馋૮(˶ᵔ ᵕ ᵔ˶)ა 新年快乐呀小伙伴 引言&#xff1a; 小伙伴们应该都有一个做游戏的梦吧&#xff1f;今天让小庄来用C语言简单实现一下我们的童年邪典贪吃蛇&#xff0c;顺便巩固我们的C语言知识&#xff0c;请安心食用~ 文章目录 贪吃蛇效果一.游戏前工作…...

rtt设备io框架面向对象学习-uart设备

目录 1.uart设备基类2.uart设备基类的子类3.初始化/构造流程3.1设备驱动层3.2 设备驱动框架层3.3 设备io管理层 4.总结5.使用 1.uart设备基类 此层处于设备驱动框架层。也是抽象类。 在/ components / drivers / include / drivers 下的serial.h定义了如下uart设备基类 struc…...

Innodb下修改事务工作流程(buffer pool、redo log、undolog)

1、在Buffer Pool中读取数据&#xff1a;当InnoDB需要更新一条记录时&#xff0c;首先会在Buffer Pool中查找该记录是否在内存中。如果没有在内存中&#xff0c;则从磁盘读取该页到Buffer Pool中。 2、记录UndoLog&#xff1a;在修改操作前&#xff0c;InnoDB会在Undo Log中记…...

redis为什么使用跳跃表而不是树

Redis中支持五种数据类型中有序集合Sorted Set的底层数据结构使用的跳跃表&#xff0c;为何不使用其他的如平衡二叉树、b树等数据结构呢&#xff1f; 1&#xff0c;redis的设计目标、性能需求&#xff1a; redis是高性能的非关系型&#xff08;NoSQL&#xff09;内存键值数据…...

【matalab】基于Octave的信号处理与滤波分析案例

一、基于Octave的信号处理与滤波分析案例 GNU Octave是一款开源软件&#xff0c;类似于MATLAB&#xff0c;广泛用于数值计算和信号处理。 一个简单的信号处理与滤波分析案例&#xff0c;说明如何在Octave中生成一个有噪声的信号&#xff0c;并设计一个滤波器来去除噪声。 首…...

Elasticsearch:特定领域的生成式 AI - 预训练、微调和 RAG

作者&#xff1a;来自 Elastic Steve Dodson 有多种策略可以将特定领域的知识添加到大型语言模型 (LLM) 中&#xff0c;并且作为积极研究领域的一部分&#xff0c;正在研究更多方法。 对特定领域数据集进行预训练和微调等方法使 LLMs 能够推理并生成特定领域语言。 然而&#…...

HarmonyOS—UI 开发性能提升的推荐方法

开发者若使用低性能的代码实现功能场景可能不会影响应用的正常运行&#xff0c;但却会对应用的性能造成负面影响。本章节列举出了一些可提升性能的场景供开发者参考&#xff0c;以避免应用实现上带来的性能劣化。 使用数据懒加载 开发者在使用长列表时&#xff0c;如果直接采用…...

84 CTF夺旗-PHP弱类型异或取反序列化RCE

目录 案例1&#xff1a;PHP-相关总结知识点-后期复现案例2&#xff1a;PHP-弱类型对比绕过测试-常考点案例3&#xff1a;PHP-正则preg_match绕过-常考点案例4&#xff1a;PHP-命令执行RCE变异绕过-常考点案例5&#xff1a;PHP-反序列化考题分析构造复现-常考点涉及资源&#xf…...

Duilib List 控件学习

这是自带的一个示例; 一开始运行的时候List中是空的,点击Search按钮以后就填充列表框; 先看一下列表框列头是在xml文件中形成的; <List name="domainlist" bkcolor="#FFFFFFFF" ... menu="true"> <ListHeader height="24…...

详细了解Node.js的配置与使用!

详细了解Node.js的配置与使用&#xff01; Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。它允许开发者在服务器端运行 JavaScript&#xff0c;从而实现全栈 JavaScript 开发。本文将介绍 Node.js 的配置和 npm 的应用。 一、Node.js 配置 下载与安装 首先&…...

OpenCV 移动最小二乘图像变形

文章目录 一、简介二、实现代码三、实现效果参考文献一、简介 在现实生活中,我们常常应用一些刚性的变换来实现物体的旋转平移,对于非刚性的变换我们都没有在意,其实这种变换也是无处不在的,如我们经常看的动画就可以通过一些非刚性的变换达到一些非常夸张的效果。这里,我…...

【深度学习】S2 数学基础 P4 概率论

目录 基本概率论概率论公理随机变量 多个随机变量联合概率条件概率贝叶斯定理求和法则独立性 期望与方差小结 基本概率论 机器学习本质上&#xff0c;就是做出预测。而概率论提供了一种量化和表达不确定性水平的方法&#xff0c;可以帮助我们量化对某个结果的确定性程度。 在…...

跟我学c++中级篇——静态多态

一、多态 Polymorphism&#xff0c;多态。学习过c的人如果不知道多态&#xff0c;基本上就是打入c内部的C程序员了。在前边曾经对多态进行过分析&#xff0c;对其中的虚函数&#xff08;虚表等&#xff09;也进行过较为详细的说明。 多态其实非常好理解&#xff0c;不要硬扣书…...

设计模式--桥接模式(Bridge Pattern)

桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;它主要是用于将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。 桥接模式主要包含以下几个角色&#xff1a; Abstraction&#xff08;抽象类&#xff09;&#xff1a;定义抽象类的…...

统计图饼图绘制方法(C语言)

统计图饼图绘制方法&#xff08;C语言&#xff09; 常用的统计图有条形图、柱形图、折线图、曲线图、饼图、环形图、扇形图。 前几类图比较容易绘制&#xff0c;饼图绘制较难。今值此介绍饼图的绘制方法。 本方法采用C语言的最基本功能&#xff1a; &#xff08; 1.&#xff09…...

洛谷C++简单题小练习day12—寻找最小值小程序

day12--寻找最小值--2.16 习题概述 题目描述 给出 n 和 n 个整数 ai​&#xff0c;求这 n 个整数中最小值是什么。 输入格式 第一行输入一个正整数 n&#xff0c;表示数字个数。 第二行输入 n 个非负整数&#xff0c;表示 1,2…a1​,a2​…an​&#xff0c;以空格隔开。 …...

相机图像质量研究(13)常见问题总结:光学结构对成像的影响--鬼影

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…...

车载诊断协议DoIP系列 —— 车辆以太网节点需求汇总

车载诊断协议DoIP系列 —— 车辆以太网节点需求汇总 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,…...

掘根宝典之C++包含对象的类,私有继承,保护继承,三大继承方式总结

包含对象成员的类 包含&#xff0c;组合和层次化&#xff1a;一个类里面的类成员之一是个类对象 我们来看个例子 #include<iostream> using namespace std; class AA { private:int a_; public:AA(int a):a_(a){}void A(){cout << a_ << endl;} }; class …...

第六篇:MySQL图形化管理工具

经过前五篇的学习&#xff0c;对于数据库这门技术的理解&#xff0c;我们已经在心中建立了一个城堡大致的雏形&#xff0c;通过命令行窗口&#xff08;cmd&#xff09;快速上手了【SQL语法-DDL-数据定义语言】等相关命令 道阻且长&#xff0c;数据库技术这一宝藏中还有数不清的…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...

React核心概念:State是什么?如何用useState管理组件自己的数据?

系列回顾&#xff1a; 在上一篇《React入门第一步》中&#xff0c;我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目&#xff0c;并修改了App.jsx组件&#xff0c;让页面显示出我们想要的文字。但是&#xff0c;那个页面是“死”的&#xff0c;它只是静态…...

GraphRAG优化新思路-开源的ROGRAG框架

目前的如微软开源的GraphRAG的工作流程都较为复杂&#xff0c;难以孤立地评估各个组件的贡献&#xff0c;传统的检索方法在处理复杂推理任务时可能不够有效&#xff0c;特别是在需要理解实体间关系或多跳知识的情况下。先说结论&#xff0c;看完后感觉这个框架性能上不会比Grap…...

【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析

1. 元器件定义与技术特点 TPS54618CQRTERQ1 是德州仪器&#xff08;TI&#xff09;推出的一款 汽车级同步降压转换器&#xff08;DC-DC开关稳压器&#xff09;&#xff0c;属于高性能电源管理芯片。核心特性包括&#xff1a; 输入电压范围&#xff1a;2.95V–6V&#xff0c;输…...

新版NANO下载烧录过程

一、序言 搭建 Jetson 系列产品烧录系统的环境需要在电脑主机上安装 Ubuntu 系统。此处使用 18.04 LTS。 二、环境搭建 1、安装库 $ sudo apt-get install qemu-user-static$ sudo apt-get install python 搭建环境的过程需要这个应用库来将某些 NVIDIA 软件组件安装到 Je…...