[C/C++]天天酷跑游戏超详细教程-上篇

  •  个人主页:北·海
  •  🎐CSDN新晋作者
  •  🎉欢迎 👍点赞✍评论⭐收藏
  • ✨收录专栏:C/C++
  • 🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!🤗

天天酷跑,一款童年游戏,主要是进行跳跃操作,和躲避障碍物,该结主要实现背景图的连续播放,跳跃,与障碍物创建 


一.游戏的展示效果


 二.本节开发日志

   1.创建项目
    2.导入素材
    3.创建游戏界面
        实际的开发流程
         对于初学者,最好的开发方式,从用户界面入手

      选择图形库或者其他引擎
      天天酷跑,是基于easyx图形库的
      1)创建游戏窗口
      2)实现游戏背景
        a.3重背景不同的速度同时移动
        b.循环滚动背景的实现
      3)实现游戏背景
        a.加载背景资源
        b.渲染 (背景知识 : 坐标)
        遇到问题 : 背景图片的png格式图片出现黑色 使用putimagePNG2接口

        4)创建人物

        5)创建障碍物小乌龟

三.素材

在主页有放置

四.游戏实现

    1)创建C++项目将素材导入项目

#include <iostream>

using namespace std;

int main(){



return 0;
}

 2)游戏初始化

对于新手而言,建议拿到游戏的时候,从游戏的背景图进行入手,由于在游戏边玩边从磁盘加载资源,这样会影响游戏的体验,这也就是为什么王者荣耀进去时候要加载的原因,都是在开始游戏之前先把资源加载到项目里面,我们就可以在游戏开始之前进行创建一个用于初始化的函数,用于专门加载这些资源

需要用到的头文件 : graphics.h,这个需要安装easyx图形库,可在该官网进行下载安装

需要用到的函数    :   loadimage用于将资源从磁盘加载进来

                                 putimagePNG2,自定义的接口用于解决png图片出现黑边,和将加载的图片渲染到屏幕上,在主页文章有介绍该接口

                                  initgraph : 用于创建游戏窗口

                                   sprintf函数,可以对字符串进行格式化,改每个图片的路径

IMAGE: 用于存放图片资源

  

 1.实现游戏窗口的创建与游戏背景的加载

#include <iostream>
#include <graphics.h>

//窗口的大小,一般在开发中由项目经理规定,定义为宏不仅可以增强代码的可读性还可以增强代码的健壮性
#define WIN_WIDTH 1012
#define WIN_HEIGHT 396  
using namespace std;

IMAGE imgBg[3];

void init(){

	//创建游戏窗口
	initgraph(WIN_WIDTH, WIN_HEIGHT);

	//加载游戏背景
	char name[64];
	for (int i = 0; i < 3; i++) {
		//"res/bg001.png  res/bg002.png
		sprintf_s(name, "res/bg%03d.png", i + 1);
		loadimage(&imgBgs[i], name);
	}

}

int main(){

init();//用于初始化

return 0;
}

 2.渲染游戏背景图,可以创建一个专门渲染图片的函数updataBg()

这边不太会搞视频展示图,所以就简单描述一下,背景图往左连绵不断的走,有三层,草坪,山,天空,既然能连绵不断,这个实现的方法拿图来解释

由于由三层,每层的y坐标都是不同的,y坐标可以测量出来,由于背景需要滚动,原理是移动当前背景图,使其向左移动,当图片的最右边达到游戏窗口的最左边时候,重新复原图片的位置,使图片的最左边到达窗口的最左边,进行循环,循环的时候,三层图片以不同的速度进行移动,所以创建一个数组bgSpeed,用于存放三个图片的速度,bgX数组用于存放当前的x值,由于游戏是个死循环,所以除了初始化,其余函数套在while(1)循环里

int bgSpeed[3] = {1,2,4};
int bgX[3];//背景图片的x坐标

//渲染游戏背景
void updateBg() {
	putimagePNG2(bgX[0], 0, WIN_WIDTH,&imgBgs[0]);
	putimagePNG2(bgX[1], 119,WIN_WIDTH, &imgBgs[1]);
	putimagePNG2 (bgX[2], 330, WIN_WIDTH,&imgBgs[2]);

}

void init(){

//for循环里,添加bgX[i] = 0 ;给变量进行初始化

}
int main(){

'''
init();

while(1){
updateBg();
}
...
}

 3.由于上面渲染的渲染背景图还是静态的,没有移动,因为bgx并没有改变,此时需要一个专门改变游戏数据的函数,fly函数吧

void fly(){

for(int i =  0 ;i<3;i++){

bgX[i] -=bgSpeed[i];//使每层图片减去他对应的速度


//做一个判断,当达到最左边时候,复位图片的位置

if(bgX[i] <=-WIN_WIDTH){
bgX[i] = 0;

}

}
}

4.此时的背景图已经开始滚动了,但是还有个小bug,因为这个渲染时用循环putimage上去的,就相当于将图片打印到上面,这也会出现的情况是每层图片之间会一闪一闪的,解决这个问题的方法,是先将他们输出到缓存区,一并打印出来,用到的函数如下:

BeginBatchDraw()

EndBatchDraw();

 此时就解决了背景的第一个问题

背景图实现,程序的进度:

#include <iostream>
#include<graphics.h>
#include "tools.h"

#define WIN_WIDTH 1012
#define WIN_HEIGHT 396


using namespace std;

/*
1.先做背景
*/


IMAGE imgBgs[3];
int bgSpeed[3] = { 1,2,4 };
int bgX[3];


void init() {

	//创建游戏窗口
	initgraph(WIN_WIDTH, WIN_HEIGHT);

	//加载背景图
	char name[64];
	for (int i = 0; i < 3; i++) {
		//"res/bg001.png  res/bg002.png
		sprintf_s(name, "res/bg%03d.png", i + 1);
		loadimage(&imgBgs[i], name);

		bgX[i] = 0;
	}


}

void updataBg() {
	putimagePNG2(bgX[0], 0,WIN_WIDTH, &imgBgs[0]);
	putimagePNG2(bgX[1], 119,WIN_WIDTH, &imgBgs[1]);
	putimagePNG2(bgX[2], 330,WIN_WIDTH, &imgBgs[2]);
}


void fly() {
	//背景图
	for (int i = 0; i < 3; i++) {
		bgX[i] -= bgSpeed[i];

		if (bgX[i] < -WIN_WIDTH) {
			bgX[i] = 0;
		}
	}
}
int main() {

	init();
	while (1) {
		BeginBatchDraw();
		updataBg();
		EndBatchDraw();

		fly();
	}
	
	system("pause");
	return 0;
}


3)创建玩家

1.由于图片在动,只需要将人物在原地就行,将人物放在最中间,由于要实现人物的运动,这个的原理是将人物的多组图片进行轮播,人物的x,y坐标可以通过数学进行算出来,此时我们先在初始化函数里加载图片,在初始化函数里计算出人物的x,y坐标,由于人物的轮播,可以传创建一个帧序列

//人物的背景图
IMAGE imgHero[12];
int heroX;
int heroY;
int heroIndex;//帧序号

void init(){

...
//加载人物的图片,仍然老套路,用到sprintf函数
	for (int i = 0; i < 12; i++) {
		sprintf(name, "res/hero%d.png", i + 1);
		loadimage(&imgHero[i], name);
	}
	//人物初始化
	heroX = WIN_WIDTH * 0.5 - imgHero[0].getwidth() * 0.5;
	heroY = 345 - imgHero[0].getheight();
	heroIndex = 0;

}

由于帧序列要改变才能实现轮播,所以需要在数据层的fly函数,进行修改帧序列

void fly(){

....

//修改帧序列,
/*heroIndex++;//如果使用这种方法的话,当进行越界,我们需要的是从1-12进行循环,所以我们用取余数进行实现
*/

heroIndex = (heroIndex+1)%12;

}

数据也可也可以改变了,我们需要将人物的图片渲染在窗口中,在main函数中只需要一条代码

int main(){

...

//实现人物的奔跑
putimagePNG2(heroX, heroY, WIN_WIDTH , &imgHero[heroIndex]);
...
}

效果图

这样人物就可以原地跑起来了,解决了第二个问题

4)实现玩家的跳跃

1.人物的跳跃是当玩家按下按键后,人物的y坐标开始上升,当达到某个高度后,然后下落

先来实现用户点击函数keyEvent(),由于只需要改变y坐标,底层的数据变化实在fly函数里面,我们只需要获取到用户的点击之后,给个可以改变y值得信号即可

用到的_kbhit()函数和_getch()函数都必须包含头文件conio.h

问题 : 都是从键盘获取一个字符为什么不用scanf()而用_getch()

答:如果使用scanf函数, 当输入数据,必须按回车,才能将数据输入进去,此时不按回车的话,程序会等待用户按回车键,此时的程序就卡在这里等待了,而用_hbhit()函数,不用等待,直接按下就可以输入进去

void keyEvent(){

//先接收用户得鼠标消息
    char ch =  0 ;
    if(_kbhit()){
        ch = _getch();
        if(ch ===' '){
        jump();
        }
    }
}

实现初始化顺便打开可跳跃得按钮 

//全局变量
bool heroJump;//跳跃状态
int jumpHeightMax;//跳跃得最大高度
int heroJumpOff;//跳跃得偏移量

void init(){

...
//对跳跃得数据进行初始化
	//跳跃初始化
	heroJump = false;
	jumpHeightMax = 345 - imgHero[0].getheight() - 120;
	heroJumpOff = -4;

}

void jump(){

heroJump = true;

}

在fly函数里改变底层数据

void fly() {

...
	//实现跳跃
	if (heroJump) {
		if (heroY < jumpHeightMax) {
			heroJumpOff = 4;//+ (-4)等于向上走,+4等于向下走
		}

		heroY += heroJumpOff;
		if (heroY > 345 - imgHero[0].getheight()) {
			//达到地面
			heroJump = false;
			heroJumpOff = -4;
		}
	}
}

 此时的英雄就可以进行跳跃了

这样人物就可以跳跃起来了,就能跳跃障碍物了,解决了第三个问题,此时还面临一个小bug,就是在当跳跃的途中,这个人物还处于一个跑步的状态,影响了用户体验,解决这个问题,我们就可以在改变底层数据里改部分代码,如果处于起跳状态则不更新帧序列,否则不跳的时候更新帧序列,以下是改变之后的渲染代码:

//人物跳跃
	if (heroJump) {

		if (heroY < jumpHeightMax) {
			heroJumpOff = 4;
		}

		heroY += heroJumpOff;


		if (heroY > 345 - imgHero[0].getheight()) {
			heroJump = false;
			heroJumpOff = -4;
		}
	}
	else {
		//heroIndex++ 这种方式会越界
		heroIndex = (heroIndex + 1) % 12;
	}

这样就解决了这个小bug,以上实现了背景图的轮播,人物的动态化,和人物的起跳,主要学到了,将渲染层,数据层分开,其他小的功能进行分支化,将main函数写的简介,实现功能模块化,接下来就可以实现障碍物了

5)障碍物小乌龟的实现

1.障碍物有许多种,先实现一种,其他的在做优化,依旧是老套路,初始化里面加载资源,渲染层进行打印图片,fly里面改变数据

2.先将小乌龟设置为静态的,优化时候也可加个帧序列实现动态的

定义小乌龟的变量

//全局状态
//小乌龟
IMAGE imgTortoise;
//小乌龟存在开关
bool torToiseExist;
int torToiseX;
int torToiseY;

 将小乌龟进行初始化

//初始化小乌龟
void init(){

...
	//小乌龟初始化
	loadimage(&imgTortoise, "res/t1.png");
	torToiseY = 345 + 5 - imgTortoise.getheight();
	torToiseExist = false;

}

从底层数据方面对小乌龟进行创建与使其移动

编程技巧:在创建小乌龟时候,如果直接写

void fly(){
...
	//创建小乌龟
	static int frameCount = 0;
	static int enemyFre = 100;
	frameCount++;
	if (frameCount > enemyFre) {
		frameCount = 0;
		enemyFre = 100+ rand() % 50;
		//创建障碍物
		if (!torToiseExist) {
			torToiseExist = true;
			torToiseX = WIN_WIDTH;
		}
	}


  //使小乌龟的运动,运动应该于草坪的移动速度保持一致,才能显得静止在草坪上
	if (torToiseExist) {
		torToiseX -= bgSpeed[2];
		if (torToiseX < -imgTortoise.getwidth()) {
			torToiseExist = false;
		}
	}

}

将小乌龟渲染出来

void updateEnemy() {
	//渲染小乌龟
	if (torToiseExist) {
		putimagePNG2(torToiseX, torToiseY,WIN_WIDTH, &imgTortoise);
	}
}

 将其函数在main函数中调用,和渲染人物一起渲染出来

 此时代码进度为:

#include <iostream>
#include<graphics.h>
#include <conio.h>
#include "tools.h"

#define WIN_WIDTH 1012
#define WIN_HEIGHT 396

using namespace std;

/*
1.先做背景
2.创建玩家
3.实现玩家跳跃
*/

//背景
IMAGE imgBgs[3];
int bgSpeed[3] = { 1,2,4 };
int bgX[3];

//人物
IMAGE imgHero[12];
int heroX;
int heroY;
int heroIndex;//帧序列

//跳跃
bool heroJump;//跳跃状态
int jumpHeightMax;//跳跃的最大高度
int heroJumpOff;

//小乌龟
IMAGE imgTortoise;
//小乌龟存在开关
bool torToiseExist;
int torToiseX;
int torToiseY;

void init() {

	//创建游戏窗口
	initgraph(WIN_WIDTH, WIN_HEIGHT);

	//加载背景图
	char name[64];
	for (int i = 0; i < 3; i++) {
		//"res/bg001.png  res/bg002.png
		sprintf_s(name, "res/bg%03d.png", i + 1);
		loadimage(&imgBgs[i], name);

		bgX[i] = 0;
	}

	//加载人物背景图
	for (int i = 0; i < 12; i++) {
		sprintf(name, "res/hero%d.png", i + 1);
		loadimage(&imgHero[i], name);
	}
	//人物的位置放在窗口的最中间,由于人物需要运动,用多组图片进行轮播,需要定义一个帧序列
	heroX = WIN_WIDTH * 0.5 - imgHero[0].getwidth() * 0.5;
	heroY = 345 - imgHero[0].getheight();
	heroIndex = 0;

	//跳跃
	heroJump = false;
	jumpHeightMax = 345 - imgHero[0].getheight() - 120;
	heroJumpOff = -4;

	//小乌龟初始化
	loadimage(&imgTortoise, "res/t1.png");
	torToiseY = 345 + 5 - imgTortoise.getheight();
	torToiseExist = false;

}

void updataBg() {
	putimagePNG2(bgX[0], 0, WIN_WIDTH, &imgBgs[0]);
	putimagePNG2(bgX[1], 119, WIN_WIDTH, &imgBgs[1]);
	putimagePNG2(bgX[2], 330, WIN_WIDTH, &imgBgs[2]);
}

void updateEnemy() {
	//渲染小乌龟
	if (torToiseExist) {
		putimagePNG2(torToiseX, torToiseY,WIN_WIDTH, &imgTortoise);
	}
}

void fly() {
	//背景图
	for (int i = 0; i < 3; i++) {
		bgX[i] -= bgSpeed[i];

		if (bgX[i] < -WIN_WIDTH) {
			bgX[i] = 0;
		}
	}

	//实现跳跃
	if (heroJump) {
		if (heroY < jumpHeightMax) {
			heroJumpOff = 4;//+ (-4)等于向上走,+4等于向下走
		}

		heroY += heroJumpOff;
		if (heroY > 345 - imgHero[0].getheight()) {
			//达到地面
			heroJump = false;
			heroJumpOff = -4;
		}
	}
	else {
		//改变人物帧序列
		heroIndex = (heroIndex + 1) % 12;
	}

	//创建小乌龟
	static int frameCount = 0;
	static int enemyFre = 100;
	frameCount++;
	if (frameCount > enemyFre) {
		frameCount = 0;
		enemyFre = 100+ rand() % 50;
		//创建障碍物
		if (!torToiseExist) {
			torToiseExist = true;
			torToiseX = WIN_WIDTH;
		}
	}

	//使小乌龟的运动,运动应该于草坪的移动速度保持一致,才能显得静止在草坪上
	if (torToiseExist) {
		torToiseX -= bgSpeed[2];
		if (torToiseX < -imgTortoise.getwidth()) {
			torToiseExist = false;
		}
	}
	

}

void jump() {

//跳跃只需要改变y值即可,在底层数据管理函数实现,此时只需要给出可以改数据的信号即可
	heroJump = true;
}

void keyEvent() {
	//获取玩家键盘事件
	char ch = 0;
	if (_kbhit()) {
		ch = _getch();
		if (ch == ' ') {
			jump();
		}
	}

}
int main() {

	init();

	while (1) {
		keyEvent();
		BeginBatchDraw();
		//渲染背景
		updataBg();
		//渲染人物
		putimagePNG2(heroX, heroY, &imgHero[heroIndex]);
		//渲染障碍物
		updateEnemy();

		EndBatchDraw();

		fly();

		Sleep(30);
	}
	
	system("pause");
	return 0;
}

6)对代码进行优化

1.在main函数的最后用了一条函数sleep(30),会将程序休眠30毫秒,如果在此期间有用户的键盘输入,会降低游戏的体验性

2.在创建小乌龟时候,由于只演示了一种障碍物,而添加障碍物时候,应该建立一个专门创建障碍物的函数

先解决第一点

在tools.cpp里有getDalay,用于计算上一次调用到现在的间隔时间,在全局状态定义一个计时器timer,在定义一个刷新界面的变量update,如果update为真,则开始刷新界面,如果间隔大于30毫秒,则将刷新界面变量至于true状态,可以代替30ms的休眠间隔,增强体验感

int main() {
	init();

	while (true) {
		keyEvent();

		timer += getDelay();
		if (timer > 30) {
			timer = 0;
			update = true;
		}

		if (update) {
			update = false;
			BeginBatchDraw();
			updataBg();
			//实现人物的奔跑
			putimagePNG2(heroX, heroY, &imgHero[heroIndex]);
			//渲染障碍物
			updateEnemy();

			EndBatchDraw();

			fly();

		}
	}

	system("pause");
	return 0;
}

解决第二点,将创建小乌龟障碍物先封装为一个函数,在下一期进行改善为可随机创建多种障碍物

void creatObstacle() {

	//小乌龟初始化
	if (!torToiseExist) {
		torToiseExist = true;
		torToiseX = WIN_WIDTH;
	}

}

在原来fly函数里面,用creatObstacle()代替上面函数体内的三条语句即可


 五.本节总结

总结 : 这结实现了背景轮播图的实现,人物的创建,障碍物的创建,动态的原理就是改变帧序列,开发技巧是将渲染层,数据层分开,其他功能封装为函数,围绕这两个函数展开,将main函数变的简单明了,讲述了开发技巧,计时器的使用,改善休眠间隔的方法

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WebGL模型矩阵

前言&#xff1a;依赖矩阵库 WebGL矩阵变换库_山楂树の的博客-CSDN博客 先平移&#xff0c;后旋转的模型变换&#xff1a; 1.将三角形沿着X轴平移一段距离。 2.在此基础上&#xff0c;旋转三角形。 先写下第1条&#xff08;平移操作&#xff09;中的坐标方程式。 等式1&am…

2023年DAMA-CDGA/CDGP数据治理认证线上班到这里

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

Fooocus:一个简单且功能强大的Stable Diffusion webUI

Stable Diffusion是一个强大的图像生成AI模型&#xff0c;但它通常需要大量调整和提示工程。Fooocus的目标是改变这种状况。 Fooocus的创始人Lvmin Zhang&#xff08;也是 ControlNet论文的作者&#xff09;将这个项目描述为对“Stable Diffusion”和“ Midjourney”设计的重新…

超简单演示Android地图开发应用实例

概述 手机地图开发应用广泛&#xff0c;本实例演示了在手机上显示各种地图的方法。比如3D矢量地图、卫星地图、交通地图、夜景地图等在手机上的显示。可以根据手势自由做地图缩放&#xff0c;地图旋转等操作。代码简洁、实用&#xff0c;可以帮助你快速上手地图开发。 详细 …

【附安装包】Vm虚拟机安装Linux系统教程

软件下载 软件&#xff1a;Linux版本&#xff1a;18.0.4语言&#xff1a;简体中文大小&#xff1a;1.82G安装环境&#xff1a;VMware硬件要求&#xff1a;CPU2.0GHz 内存4G(或更高&#xff09;下载通道①丨百度网盘&#xff1a;1.Vm虚拟机15.5下载链接&#xff1a;https://pan…

视频智能分析平台EasyCVR安防视频汇聚平台助力森林公园防火安全的应用方案

一、研发背景 随着经济的发展和人们生活水平的提高&#xff0c;越来越多的人喜欢在周末去周边的森林公园旅游&#xff0c;享受大自然的美景&#xff0c;并进行野炊和烧烤等娱乐活动。然而&#xff0c;近年来由于烟蒂和烧烤碳渣等人为因素&#xff0c;森林公园火灾频繁发生。森…

【核磁共振成像】并行采集MRI

目录 一、并行成像二、SENSE重建三、SMASH重建四、灵敏度校准五、AUTO-SMASH和VD-AUTO-SMASH六、GRAPPA重建七、SPACE RIP重建算法八、PILS重建算法九、PRUNO重建算法十、UNFOLD算法 一、并行成像 并行MR成像(pMRI):相位阵列接受线圈不但各有自己专用的接受通道&#xff0c;而且…

Oracle 本地客户端连接远程 Oracle 服务端并使用 c# 连接测试

这里写自定义目录标题 前言Oracle 客户端安装先决条件下载 Oracle 客户端Oracle 客户端环境变量配置 PL/SQLPL/SQL 下载PL/SQL 配置 配置远程连接tnsnames.ora 文件配置 使用 PL/SQL 连接远程数据库使用 C# 远程访问 Oracle 数据库结语 前言 最近有一个需要使用本地的 Oracle …

Linux知识点 -- 网络基础(一)

Linux知识点 – 网络基础&#xff08;一&#xff09; 文章目录 Linux知识点 -- 网络基础&#xff08;一&#xff09;一、网络发展二、协议1.OSI七层模型2.TCP/IP五层&#xff08;或四层&#xff09;模型 三、网络传输基本流程1.局域网中的两台主机通信流程2.跨网段的两台主机间…

element侧边栏子路由点击不高亮问题

最近自己封装侧边栏 又碰到了点击子路由不高亮的问题 <template><div class"aside"><el-scrollbar :vertical"true" class"scrollbar_left_nav"><el-menu :default-active"defaultActive" :collapse"$stor…

Django基础7——用户认证系统、Session管理、CSRF安全防护机制

文章目录 一、用户认证系统二、案例&#xff1a;登陆认证2.1 平台登入2.2 平台登出2.3 login_required装饰器 三、Django Session管理3.1 Django使用Session3.1.1 Cookie用法3.1.2 Session用法 3.2 案例&#xff1a;用户登录认证 四、Django CSRF安全防护机制 一、用户认证系统…

【算法专题突破】双指针 - 有效三角形的个数(5)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;611. 有效三角形的个数 - 力扣&#xff08;Leetcode&#xff09; 我们可以根据示例1来理解这一道题目&#xff0c; 他说数组里面的数可以组成三角形三条边的个数&#x…

5G+智慧交通行业解决方案[46页PPT]

导读:原文《5G+智慧交通行业解决方案[46页PPT]》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。

【C++笔记】C++内存管理

【C笔记】C内存管理 一、C中动态内存申请的方式二、new和delete的实现原理2.1、operator new和operator delete函数 一、C中动态内存申请的方式 在C语言中我们需要动态申请空间的时候我们通常都是用malloc函数&#xff0c;但是malloc函数对自定义类型是没什么问题的&#xff0…

LNMP架构之搭建Discuz论坛

LNMP 一、编译安装Nginx1&#xff09;前置准备2&#xff09;开始编译安装3&#xff09;添加到系统服务&#xff08;systemd启动&#xff09; 二、编译安装MySQL服务1&#xff09;前置准备2&#xff09;编译安装3&#xff09;编辑配置文件4&#xff09;更改mysql安装目录和配置文…

算法面试-深度学习面试题整理(2024.8.29开始,每天下午持续更新....)

一、无监督相关&#xff08;聚类、异常检测&#xff09; 1、常见的距离度量方法有哪些&#xff1f;写一下距离计算公式。 1&#xff09;连续数据的距离计算&#xff1a; 闵可夫斯基距离家族&#xff1a; 当p 1时&#xff0c;为曼哈顿距离&#xff1b;p 2时&#xff0c;为欧…

延迟队列的理解与使用

目录 一、场景引入 二、延迟队列的三种场景 1、TTL对队列进行延迟 2、创建通用延时消息对消息延迟 3、使用rabbitmq的延时队列插件 x-delayed-message使用 父pom文件 pom文件 配置文件 config 生产者 消费者 结果 一、场景引入 我们知道可以通过TTL来对队列进行设…

【OpenCV入门】第一部分——图像处理基础

本文结构 图像处理的基本操作读取图像imread() 显示图像imshow()waitKey()destroyAllWindows() 保存图像imwrite() 复制图像copy() 获取图像属性 像素确定像素的位置获取像素的BGR值修改像素的BGR值 色彩空间GRAY色彩空间cvtColor()——从BGR色彩空间转换到GRAY色彩空间 HSV色彩…

Spring boot使用Kafka Java反序列化漏洞 CVE-2023-34040

文章目录 0.前言漏洞spring-kafka 介绍 1.参考文档2.基础介绍3.解决方案3.1. 升级版本3.2. 替代方案 4.Spring kafka 使用教程代码示例 0.前言 背景&#xff1a;公司项目扫描到 Spring-Kafka上使用通配符模式匹配进行的安全绕过漏洞 CVE-2023-20873 漏洞 中等风险 | 2023年8月…

Python框架【模板继承 、继承模板实战、类视图 、类视图的好处 、类视图使用场景、基于调度方法的类视图】(四)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…