【游戏专区】飞机大战

news2024/12/24 9:14:14

打过飞机的人都知道,不是那么好打滴,求得麻袋,甩掉你那脑子里的黄色信息。活不多说,我们开始吧。

1、easyX的原理

基于Windows图形编程,将Windows下的复杂程序过程进行封装,仅给用户提供一个简单熟悉的接口。用户对于图形库中函数的调用,最终都会由Windows底层的API实现。

2、easyX的安装

仅支持vs系列

点击跳转

平常使用那个版本就点击对应的安装按钮即可。

3,图片资源

链接:点击获取图片
提取码:1111

4,创建窗口

窗口我们需要创建多大呢,

具体实现怎么操作,我们开始写代码

窗口是有了,但是我们如何将图片绘制出来呢

5,定义飞机结构

想想我们飞机需要哪些结构,坐标,血量还有什么呢

//创建飞机结构
typedef struct Plane
{
	int x;//飞机坐标
	int y;
	bool isDie;//是否健在
	int width;//宽度
	int height;//长度
	int frame;//当前帧
	int hp;//血量
	int type;//敌机类型
}Plane;

有了飞机的结构以及初始化,我们是不是还需要将其加载进入
飞机图片

6,透明贴图函数(可直接复制,使用也是可以的)

#include "aircraft.h"

//把像素的颜色拆解出来 ARGB
typedef struct _ARGB {
	byte a;
	byte r;
	byte g;
	byte b;
}ARGB;
//把颜色拆分
ARGB color2Argb(DWORD c) {
	ARGB res;
	res.r = (byte)c;
	res.g = (byte)(c >> 8);
	res.b = (byte)(c >> 16);
	res.a = (byte)(c >> 24);
	return res;
}
DWORD argb2Color(ARGB c) {
	DWORD t = RGB(c.r, c.g, c.b);
	return ((DWORD)c.a) << 24 | t;
}
//把色彩图转成黑白图
void toGray(IMAGE* src) {
	DWORD* psrc = GetImageBuffer(src);
	for (int i = 0; i < src->getwidth() * src->getheight(); i++) {
		//获取每一个像素点的颜色值
		ARGB t = color2Argb(psrc[i]);
		//灰度图,求三个或者四个颜色值的均值
		byte arv = (t.r + t.g + t.b) / 3;
		ARGB res = { t.a,arv,arv,arv };
		psrc[i] = argb2Color(res);
	}
}
/*
* @png透明贴图
*/
void drawImg(int x, int y, IMAGE* src) {
	// 变量初始化
	DWORD* pwin = GetImageBuffer();//窗口缓冲区指针
	DWORD* psrc = GetImageBuffer(src);//图片缓冲区指针
	int win_w = getwidth();//窗口宽高
	int win_h = getheight();
	int src_w = src->getwidth();//图片宽高
	int src_h = src->getheight();
	//计算贴图的实际长宽
	int real_w = (x + src_w > win_w) ? win_w - x : src_w;//处理超出右边界
	int real_h = (y + src_h > win_h) ? win_h - y : src_h;//处理超出右边界
	if (x < 0) {//处理超出左边界
		psrc += -x;
		real_w -= -x;
		x = 0;
	}
	if (y < 0) {//处理超出右边界
		psrc += (src_w * -y);
		real_h -= -y;
		y = 0;
	}

	//修正贴图起始位置
	pwin += (win_w * y + x);
	//实现透明贴图
	for (int iy = 0; iy < real_h; iy++) {
		for (int ix = 0; ix < real_w; ix++) {
			byte a = (byte)(psrc[ix] >> 24);//计算透明通道的值[0,256] 0为完全透明 255完全不透明
			if (a > 100) {
				pwin[ix] = psrc[ix];
			}
		}
		//换到下一行
		pwin += win_w;
		psrc += src_w;
	}
}

当我们写到这里,只需要将绘制飞机的(putimage)替换成(drawLmg),就已经可以实现飞机的动态刷新了

7,飞机的移动

那我们要去移动飞机吧,不然他还只是一张图片,我们要写飞机的移动,就必须考虑它的边界问题。

知道了这些,我们就可以开始写代码了

当我们写完这个,你就会发现你的飞机走的非常快,这是我们电脑在处理帧的时候非常的迅速,所以我们还需要一个定时器,每秒刷新60帧,应该已经足够。

//参数:frameRate 帧数
void timerFunction(int frameRate) {
	clock_t startTime, currentTime;
	long elapsed;

	// 计算每一帧的毫秒数
	int ms_per_frame = 1000 / frameRate;

	// 获取初始时间
	startTime = clock();

	while (1) {
		// 获取当前时间
		currentTime = clock();

		// 计算已经过去的时间(以毫秒为单位)
		elapsed = (currentTime - startTime) * 1000;

		// 如果已经过去的时间超过了下一帧的时间间隔,则输出一帧
		if (elapsed >= ms_per_frame) {
			

			// 更新初始时间
			startTime = currentTime;
			// 暂停一段时间,使得每秒输出指定的帧率
			Sleep(1); // 暂停 1 毫秒
			break;
		}
	}
}

8,子弹的初始化绘制以及移动

现在我们就来定义子弹的结构

//子弹结构
typedef struct Bullet
{

	int x;//坐标
	int y;
	bool isDie;//是否出界面以及碰到敌机

}Bullet;

子弹的初始化,我们也可以在初始化函数中进行调用

初始化完成后,我们还需加载资源以及绘制它

//子弹图片有两张
static IMAGE img_bullet[2];


//加载子弹图片
loadimage(img_bullet + 0, "images/bullet1.png");
loadimage(img_bullet + 1, "images/bullet2.png");

但是,当我们有了这些依旧无法发射子弹,我们设计的是需要空格去发射的,所以,我们还需要再移动飞机的函数中写一个发射子弹的判断

这是因为我们发射子弹太快,重叠了,而且我们的子弹只会停留在我们发射的位置,不会移动,所有有了目标,接下来就好办多了。

我们可以写一个定时器,让它隔几微妙后才能发射

/*
类概述:
私有成员变量: std::vector<std::chrono::steady_clock::time_point> startTimes:存储每个计时器的起始时间,通过其ID进行标识。
构造函数:
Timer(): 默认构造函数。
方法:
bool hasElapsed(int ms, int id): 检查指定ID的计时器是否经过了ms毫秒。
*/
class Timer {
private:
    std::vector<std::chrono::steady_clock::time_point> startTimes;

public:
    Timer() {}

    bool hasElapsed(int ms, int id) {
        if (id >= startTimes.size()) {
            startTimes.resize(id + 1);
            startTimes[id] = std::chrono::steady_clock::now();
            return true; // Treat as elapsed since this is the first time for this timer
        }

        auto now = std::chrono::steady_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - startTimes[id]);
        if (duration.count() >= ms) {
            startTimes[id] = now;
            return true;
        }
        return false;
    }
};

接下来就是子弹的移动

所以呢,这样看我们要写的移动就是Y轴的递减过程,飞出界外或者碰到敌人,我们将其置为false就可以了。(很容易写吧)

9,创建敌机

我们现在需要什么,当然是敌人啊

我要打十个,敌人的结构我们可以直接用本机的结构,我们直接初始化敌机,当然,我们敌机的照片也是有好几种的,我这里只加载了两种敌对飞机,如果你们想,其实可以在等主机把小飞机打完之后,绘制打飞机,大飞机的血量可以多点,大飞机也可以发射子弹,当主角解决完大飞机后,可以产生一个界面吗,问其是否要继续挑战,进入下一关,逻辑也是相当简单的。

10,检测子弹是否打到敌机以及敌机是否碰到本机

到这里,我们就完成了第一关的制作,后续如果可以根据你们的意愿去做其他的处理

11,aircraft.h

#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
#include <easyx.h>
#include <chrono>
#include <vector>



#define MOVE 5
#define graph_height 700
#define graph_width 480
#define ENEMY_NUM 10//敌机数量

#define BULLET_NUM 25//子弹数量
//子弹图片有两张
static IMAGE img_bullet[2];
static IMAGE img_bk;//背景图
static IMAGE img_gamer[2];//飞机图片
static IMAGE img_enemy[2][2];//敌机图片



//创建飞机结构
typedef struct Plane
{
	int x;//飞机坐标
	int y;
	bool isDie;//是否健在
	int width;//宽度
	int height;//长度
	int frame;//当前帧
	int hp;//血量
	int type;//敌机类型
}Plane;

//子弹结构
typedef struct Bullet
{

	int x;//坐标
	int y;
	bool isDie;//是否出界面以及碰到敌机

}Bullet;
//敌机类型
enum enemyType
{
	BIG,//大飞机
	SMALL//小
};


//资源加载
void Resource();
//绘制函数
void draw(Plane* gamer,Bullet* bullet, Plane* enemy);
//初始化函数
void init(Plane* gamer, Bullet* bullet, Plane* enemy);
//透明贴图函数
void drawImg(int x, int y, IMAGE* src);
//定时器
void timerFunction(int frameRate);
//更新数据
void Updata(Plane* gamer, Bullet* bullet, Plane* enemy);
//void updateEnemyStatus(Plane* enemy);
void checkCollision(Plane* gamer,Plane* enemy, Bullet* bullet);
void createEnemy(Plane* enemy);

12,aircraft.cpp

#include "aircraft.h"

class Timer {
private:
	std::vector<std::chrono::steady_clock::time_point> startTimes;

public:
	Timer() {}
	bool hasElapsed(int ms, int id) {
		if (id >= startTimes.size()) {
			startTimes.resize(id + 1);
			startTimes[id] = std::chrono::steady_clock::now();
			return true; // 重启计数器
		}

		auto now = std::chrono::steady_clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - startTimes[id]);
		if (duration.count() >= ms) {
			startTimes[id] = now;
			return true;
		}
		return false;
	}
};
Timer timer;

void enemyHP(int i, Plane* enemy)
{
	
	int flag = rand() % 10;
	if (flag >= 0 && flag <= 1)
	{
		enemy[i].type = BIG;
		enemy[i].hp = 3;
		enemy[i].width = 169;
		enemy[i].height = 230;
	}
	else
	{
		enemy[i].type = SMALL;
		enemy[i].hp = 1;
		enemy[i].width = 57;
		enemy[i].height = 43;
	}
}
//资源加载
void Resource()
{
	
	//加载资源函数
	loadimage(&img_bk, "images/background.png");
	//加载玩家飞机图片
	loadimage(&img_gamer[0], "images/me1.png");
	loadimage(&img_gamer[1], "images/me2.png");
	//加载子弹图片
	loadimage(img_bullet + 0, "images/bullet1.png");
	loadimage(img_bullet + 1, "images/bullet2.png");
	//加载敌机图片
	loadimage(&img_enemy[0][0], "images/enemy1.png");
	loadimage(&img_enemy[0][1], "images/enemy1.png");
	loadimage(&img_enemy[1][0], "images/enemy2.png");
	loadimage(&img_enemy[1][1], "images/enemy2.png");
}

//绘制桌面
void draw_graph()
{
	//绘制函数
	putimage(0, 0, &img_bk);
}
//绘制飞机
void draw_gamer(Plane* gamer)
{
	//通过初始化的飞机结构,确定其位置和加载哪一张图片
	drawImg(gamer->x, gamer->y, &img_gamer[gamer->frame]);
	gamer->frame = (++(gamer->frame)) % 2;
}
//绘制子弹
void draw_bullet(Bullet* bullet)
{
	for (int i = 0; i < BULLET_NUM; i++)
	{
		//发射绘制第一张
		if (bullet[i].isDie)
		{
			drawImg(bullet[i].x, bullet[i].y, img_bullet + 0);
		}
		//碰到敌人或者墙壁我们绘制第二张(后续我们会更改)
		if(bullet[i].y == 0)
		{
			drawImg(bullet[i].x, bullet[i].y, img_bullet + 1);
		}

	}
}
 绘制敌机
//void enemyDraw(Plane* enemy) {
//	// 绘制敌机
//	for (int num = 0; num < ENEMY_NUM; num++) {
//		if (!enemy[num].isDie) {
//			if (enemy[num].type == BIG) {
//				drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][0]);
//				drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][1]);
//			}
//			else if (enemy[num].type == SMALL) {
//				drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][0]);
//				drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][1]);
//			}
//		}
//	}
//}

// 创建敌机
void createEnemy(Plane* enemy) {
	for (int i = 0; i < ENEMY_NUM; i++)
	{
		if (!enemy[i].isDie)
		{
			//创建随机坐标
			enemy[i].x = rand() % (getwidth() - 60);
			enemy[i].y = 0;
			enemyHP(i, enemy);
			enemy[i].isDie = true;//生成敌机
			break;
		}
	}
}
// 绘制敌机
void enemyDraw(Plane* enemy) {
	
	//static int count = 0;
	
	for (int num = 0; num < ENEMY_NUM; num++)
	{
		if (enemy[num].isDie)
		{
			//printf("%d ", count++);

			if (enemy[num].type == BIG)
			{
				drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][0]);
				drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][1]);
			}
			else
			{
				drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][0]);
				drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][1]);
			}
		}

	}

}
//void enemyDraw(Plane* enemy) {
//	//绘制敌机
//	for (int num = 0; num < ENEMY_NUM; num++)
//	{
//		if (enemy[num].isDie)
//		{
//			if (enemy[num].type == BIG)
//			{
//				drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][0]);
//				drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][1]);
//			}
//			else
//			{
//				drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][0]);
//				drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][1]);
//			}
//		}
//	}
//
//}
//绘制函数
void draw(Plane* gamer,Bullet* bullet, Plane* enemy)
{

	draw_graph();
	draw_gamer(gamer);
	draw_bullet(bullet);

	enemyDraw(enemy);

}

void init_gamer(Plane* gamer,int x,int y)
{
	gamer->x = x;
	gamer->y = y;
	gamer->isDie = false;
	gamer->frame = 0;
	gamer->hp = 100;
	gamer->width = 102;
	gamer->height = 126;
}

void init_bullet(Bullet* bullet)
{
	for (int i = 0; i < BULLET_NUM; i++)
	{
		bullet[i].isDie = false;
		//bullet[i].x = x;
		//bullet[i].y = y;//我们这里通过按下空格键再去绘制它,所以在这里我们并不需要去更新坐标
	}
}

void init_enemy(Plane* enemy)
{
	for (int i = 0; i < ENEMY_NUM; i++)
	{
	
		enemy[i].isDie = false;

	}
}
//初始化函数
void init(Plane* gamer, Bullet* bullet, Plane* enemy)
{
	//我们在初始化的时候就可以将,资源加载
	Resource();
	//初始化飞机
	init_gamer(gamer, ((getwidth() - img_gamer->getwidth()) / 2),
		(getheight() - img_gamer->getheight()));
	//(gamer->x) / 2, gamer->y + img_bullet->getheight()
	init_bullet(bullet);
	init_enemy(enemy);
}


void timerFunction(int frameRate) {
	clock_t startTime, currentTime;
	long elapsed;

	// 计算每一帧的毫秒数
	int ms_per_frame = 1000 / frameRate;

	// 获取初始时间
	startTime = clock();

	while (1) {
		// 获取当前时间
		currentTime = clock();

		// 计算已经过去的时间(以毫秒为单位)
		elapsed = (currentTime - startTime) * 1000;

		// 如果已经过去的时间超过了下一帧的时间间隔,则输出一帧
		if (elapsed >= ms_per_frame) {
			

			// 更新初始时间
			startTime = currentTime;
			// 暂停一段时间,使得每秒输出指定的帧率
			Sleep(1); // 暂停 1 毫秒
			break;
		}
	}
}

void createBullet(Plane* gamer, Bullet* bullet)
{
	//循环遍历找到可用的子弹,进行发射
	for (int i = 0; i < BULLET_NUM; i++)
	{
		if (!bullet[i].isDie)
		{
			bullet[i].isDie = true;
			bullet[i].x = gamer->x + img_gamer->getwidth() / 2;
			bullet[i].y = gamer->y;
			break;
		}
	}
}
//移动飞机,发射子弹
void palygamer(Plane* gamer, Bullet* bullet)
{

	if (GetAsyncKeyState(VK_UP) && gamer->y > 0)
	{
		gamer->y -= MOVE;
	}
	if (GetAsyncKeyState(VK_DOWN) && gamer->y + img_gamer->getheight() < getheight())
	{
		gamer->y += MOVE;
	}
	if (GetAsyncKeyState(VK_LEFT) && gamer->x + img_gamer->getwidth() / 2 > 0)
	{
		gamer->x -= MOVE;
	}
	if (GetAsyncKeyState(VK_RIGHT) && gamer->x + img_gamer->getwidth() / 2 < getwidth())
	{
		gamer->x += MOVE;
	}
	if (GetAsyncKeyState(VK_SPACE) && timer.hasElapsed(100, 1))
	{
		createBullet(gamer, bullet);
	}
}
//子弹移动
void movebullet(Bullet* bullet)
{
	for (int i = 0; i < BULLET_NUM; i++)
	{
		if (bullet[i].isDie)
		{
			bullet[i].y -= MOVE;
			//如果子弹跑出窗口,则置为false
			if (bullet[i].y < 0)
			{
				bullet[i].isDie = false;
			}
		}
	}
}

//void moveEnemy(Plane* enemy)
//{
//	for (int i = 0; i < ENEMY_NUM; i++)
//	{
//		if (enemy[i].isDie)
//		{
//			enemy[i].y += 3;
//			if (enemy[i].y > getheight() || enemy[i].hp <= 0)
//			{
//				enemy[i].isDie = false;
//			}
//		}
//	}
//}
// 移动敌机
void moveEnemy(Plane* enemy) {
	for (int i = 0; i < ENEMY_NUM; i++)
	{
		if (enemy[i].isDie)
		{
			enemy[i].y += 3;
			if (enemy[i].y > getheight())
			{
				enemy[i].isDie = false;
			}
		}
	}
}
//碰撞检测
void checkCollision(Plane* gamer,Plane* enemy, Bullet* bullet)
{

	for (int i = 0; i < ENEMY_NUM; i++)
	{
		if (!enemy[i].isDie)
			continue;
		for (int j = 0; j < BULLET_NUM; j++)
		{
			if (!bullet[j].isDie)
				continue;
			if (bullet[j].x > enemy[i].x &&
				bullet[j].x < enemy[i].x + enemy[i].width &&
				bullet[j].y > enemy[i].y &&
				bullet[j].y < enemy[i].y + enemy[i].height)
			{
				bullet[j].isDie = false;
				enemy[i].hp--;

			}
		}
		if (enemy[i].hp <= 0) enemy[i].isDie = false;
	}
	for (int i = 0; i < ENEMY_NUM; i++)
	{
		if (gamer->x + gamer->width >= enemy[i].x &&
			gamer->x <= enemy[i].x + enemy[i].width &&
			gamer->y <= enemy[i].y + enemy[i].height &&
			gamer->y + gamer->height >= enemy[i].y)
		{
			//可以给一个窗口,问是否需要重来,或者可以加一些关机操作,都是没有问题的,根据你们想要的逻辑去改代码即可
			exit(1);
		}
	}


}

//void checkCollision(Plane* enemy, Bullet* bullet) {
//	if (!enemy || !bullet) {
//		// 参数验证失败,输出错误信息并返回
//		printf("Error: Invalid parameters in checkCollision function.\n");
//		return;
//	}
//
//	for (int j = 0; j < ENEMY_NUM; j++) {
//		if (!enemy[j].isDie) {
//			continue;
//		}
//		for (int i = 0; i < BULLET_NUM; i++) {
//			if (!bullet[i].isDie) {
//				continue;
//			}
//
//			if (bullet[i].x > enemy[j].x && bullet[i].x < (enemy[j].x + enemy[j].width)
//				&& bullet[i].y > enemy[j].y && (bullet[i].y < enemy[j].y + enemy[j].height)) {
//				bullet[i].isDie = false;
//				enemy[j].hp--;
//			}
//		}
//	}
//}

//void updateEnemyStatus(Plane* enemy) {
//	if (!enemy) {
//		// 参数验证失败,输出错误信息并返回
//		printf("Error: Invalid parameters in updateEnemyStatus function.\n");
//		return;
//	}
//
//	for (int j = 0; j < ENEMY_NUM; j++) {
//		if (enemy[j].hp == 0) {
//			enemy[j].isDie = false;
//		}
//	}
//}

//更新数据
void Updata(Plane* gamer,Bullet* bullet, Plane* enemy)
{
	//玩家移动
	palygamer(gamer, bullet);
	//子弹移动
	movebullet(bullet);
	//创建敌机
	if (timer.hasElapsed(1000, 1))
	{
		//printf("6");
		createEnemy(enemy);
	}
	//移动敌机
	moveEnemy(enemy);
	//子弹打到飞机
	checkCollision(gamer,enemy, bullet);
}

13,tools.cpp

#include "aircraft.h"

//把像素的颜色拆解出来 ARGB
typedef struct _ARGB {
	byte a;
	byte r;
	byte g;
	byte b;
}ARGB;
//把颜色拆分
ARGB color2Argb(DWORD c) {
	ARGB res;
	res.r = (byte)c;
	res.g = (byte)(c >> 8);
	res.b = (byte)(c >> 16);
	res.a = (byte)(c >> 24);
	return res;
}
DWORD argb2Color(ARGB c) {
	DWORD t = RGB(c.r, c.g, c.b);
	return ((DWORD)c.a) << 24 | t;
}
//把色彩图转成黑白图
void toGray(IMAGE* src) {
	DWORD* psrc = GetImageBuffer(src);
	for (int i = 0; i < src->getwidth() * src->getheight(); i++) {
		//获取每一个像素点的颜色值
		ARGB t = color2Argb(psrc[i]);
		//灰度图,求三个或者四个颜色值的均值
		byte arv = (t.r + t.g + t.b) / 3;
		ARGB res = { t.a,arv,arv,arv };
		psrc[i] = argb2Color(res);
	}
}
/*
* @png透明贴图
*/
void drawImg(int x, int y, IMAGE* src) {
	// 变量初始化
	DWORD* pwin = GetImageBuffer();//窗口缓冲区指针
	DWORD* psrc = GetImageBuffer(src);//图片缓冲区指针
	int win_w = getwidth();//窗口宽高
	int win_h = getheight();
	int src_w = src->getwidth();//图片宽高
	int src_h = src->getheight();
	//计算贴图的实际长宽
	int real_w = (x + src_w > win_w) ? win_w - x : src_w;//处理超出右边界
	int real_h = (y + src_h > win_h) ? win_h - y : src_h;//处理超出右边界
	if (x < 0) {//处理超出左边界
		psrc += -x;
		real_w -= -x;
		x = 0;
	}
	if (y < 0) {//处理超出右边界
		psrc += (src_w * -y);
		real_h -= -y;
		y = 0;
	}

	//修正贴图起始位置
	pwin += (win_w * y + x);
	//实现透明贴图
	for (int iy = 0; iy < real_h; iy++) {
		for (int ix = 0; ix < real_w; ix++) {
			byte a = (byte)(psrc[ix] >> 24);//计算透明通道的值[0,256] 0为完全透明 255完全不透明
			if (a > 100) {
				pwin[ix] = psrc[ix];
			}
		}
		//换到下一行
		pwin += win_w;
		psrc += src_w;
	}
}

14,main.cpp


#include "aircraft.h"


int main()
{

	Plane gamer;
	Bullet bullet[BULLET_NUM];
	Plane enemy[ENEMY_NUM];
	//创建窗口函数
	initgraph(graph_width, graph_height, 1);
	//获取当前时间

	init(&gamer, bullet, enemy);

	BeginBatchDraw();//双缓冲
	while (1)
	{
		draw(&gamer, bullet, enemy);
		
		FlushBatchDraw();//立即刷新缓冲区
		Updata(&gamer, bullet, enemy);
		timerFunction(60);
		//checkCollision(enemy, bullet);
		


	}

	EndBatchDraw();//结束缓冲

	return 0;
}

15,每期一问

上期答案:
#define MY_OFFSETOF(s, m) ((size_t)(&(((s*)0)->m)))

本期问题:

环形链表的约瑟夫问题_牛客题霸_牛客网

下期再见!

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

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

相关文章

.NET .exe .dll 反编译 程序反编译 程序逆向

反编译是对程序进行逆向分析、研究&#xff0c;以推导出软件产品所使用的思路、原理、结构、算法、处理过程、运行方法等设计要素。 反编译.NET程序需要使用专门的反编译工具 &#x1f9ff;使用dotPeek进行反编译 1.下载dotPeek dotPeek&#xff1a;JetBrains 出品的免费 .N…

视频质量评价 SSIM 算法详细介绍

SSIM SSIM(Structural Similarity Index Measure)是一种用于衡量两幅图像之间相似度的指标,是属于全参考视频质量评价算法范畴;它在图像质量评估领域得到了广泛的应用。SSIM是基于人类视觉系统的特性设计的,它考虑了图像的亮度、对比度和结构信息。SSIM的值范围在-1到1之…

【状态压缩 并集查找 图论】2157. 字符串分组

本文涉及知识点 状态压缩 并集查找 图论 LeetCode2157. 字符串分组 给你一个下标从 0 开始的字符串数组 words 。每个字符串都只包含 小写英文字母 。words 中任意一个子串中&#xff0c;每个字母都至多只出现一次。 如果通过以下操作之一&#xff0c;我们可以从 s1 的字母集…

SQLite FTS3 和 FTS4 扩展(三十二)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite 的命令行 Shell(三十一&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 概述 FTS3 和 FTS4 是 SQLite 虚拟表模块&#xff0c;允许用户执行 对一组文档进行全文搜索。最常见&#xff08;和最有效…

csdn的编写教程(官方给的)

自定义的目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个注脚…

CCF-CSP真题《202312-3 树上搜索》思路+c++满分题解

想查看其他题的真题及题解的同学可以前往查看&#xff1a;CCF-CSP真题附题解大全 问题描述 试题编号&#xff1a;202312-3试题名称&#xff1a;树上搜索时间限制&#xff1a;1.0s内存限制&#xff1a;512.0MB问题描述&#xff1a; 题目背景 问题描述 输入格式 输出格式 样…

【Leetcode每日一题】 穷举vs暴搜vs深搜vs回溯vs剪枝_全排列 - 全排列(难度⭐⭐)(62)

1. 题目解析 题目链接&#xff1a;46. 全排列 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 回溯算法是一种通过探索所有可能的候选解来找出所有解的算法。当候选解被确认不是一个解&#xff08;或者至少不是最后一…

【QT进阶】Qt http编程之后端API测试工具postman使用介绍

往期回顾 【QT进阶】Qt Web混合编程之使用ECharts显示各类折线图等-CSDN博客 【QT进阶】Qt Web混合编程之实现ECharts数据交互动态修改-CSDN博客 【QT进阶】Qt http编程之http与https简单介绍-CSDN博客 【QT进阶】Qt http编程之后端API测试工具postman使用介绍 其实这个工具的…

springboot是什么?

可以应用于Web相关的应用开发。 选择合适的框架&#xff0c;去开发相关的功能&#xff0c;会有更高的效率。 为什么Spring Boot才是你该学的!学java找工作必会技能!在职程序员带你梳理JavaEE框架_哔哩哔哩_bilibili java工程师的必备技能 Spring是Java EE领域的企业级开发宽…

VSCode 目录折叠展开、缩进深度设置

1、VSCode 目录折叠展开设置 运行 Visual Studio Code &#xff0c;按 Ctrl &#xff0c;打开设置 输入Explorer:Compact Folders&#xff0c;取消勾选 或者在设置文件上添加 "explorer.compactFolders": false2、VSCode 目录缩进深度设置 输入Workbench Tree:…

计算机视觉——OpenCV Python位运算与图像掩码

概述 位运算与图像掩码的结合允许对图像的特定区域进行精确的操作。通过使用位运算&#xff08;如AND、OR、XOR和NOT&#xff09;&#xff0c;可以基于掩码的选择性地修改图像数据。位运算与图像掩码结合使用的一些关键点和应用场景&#xff1a; 选择性修改&#xff1a; 通过位…

视频质量评价 PSNR 算法详细介绍

PSNR PSNR(Peak Signal-to-Noise Ratio,峰值信噪比)是一种常用的评价图像质量的指标,尤其在图像压缩和图像处理领域。它基于最大可能的图像信号功率和图像的噪声功率之间的比率,通常用于衡量图像恢复或图像压缩算法的效果。 原理 PSNR是基于MSE(Mean Squared Error,均…

【网站项目】高校毕业论文管理系统小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【java解决线程间变量不可见性的方案】

解决线程间变量不可见性的方案 一、 背景 所有的实例变量和类变量都存储在主内存&#xff0c;但每个线程都有自己的工作内存&#xff0c;保留了主内存的共享变量的副本&#xff0c;线程修改的是共享变量&#xff0c;但是每个线程每次只能读取工作内存里的值&#xff0c;所以会…

Flink窗口机制

1.窗口的概念 时间是为窗口服务的。窗口是什么&#xff1f;为什么会有窗口呢&#xff1f; &#xff08;1&#xff09;Flink要处理的数据&#xff0c;一般是从Kafka过来的流式数据&#xff0c;如果只是单纯地统计流的数据量&#xff0c;是没办法统计的。 &#xff08;2&#xff…

2024蓝桥杯每日一题(组合计数)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;计算系数 试题二&#xff1a;求组合数1 试题三&#xff1a;求组合数2 试题四&#xff1a;杨辉三角形 试题一&#xff1a;计算系数 【题目描述】 给定一个多项式 (axby)k&#xff0c;请…

Google Earth Engine 洪水制图 - 使用 Sentinel-1 SAR GRD

Sentinel-1 提供从具有双极化功能的 C 波段合成孔径雷达 (SAR) 设备获得的信息。该数据包括地面范围检测 (GRD) 场景,这些场景已通过 Sentinel-1 工具箱进行处理,以创建经过校准和正射校正的产品。该集合每天都会更新,新获得的资产会在可用后两天内添加。 该集合包含所有 G…

【研发管理】产品经理知识体系-产品创新管理

导读&#xff1a; 产品创新管理对企业的发展具有深远的影响&#xff0c;它不仅是企业保持竞争优势的关键&#xff0c;也是推动企业持续稳定发展的重要动力。因此&#xff0c;企业应高度重视产品创新管理&#xff0c;并采取有效的策略和方法来推动产品创新活动的开展。对于产品经…

.NET 邮件发送 SMTP邮件发送

SMTP&#xff08;Simple Mail Transfer Protocol&#xff09;是用于电子邮件传输的规则集&#xff0c;可以从邮件客户端向接收电子邮件服务器发送、中继或转发邮件。发件人可使用SMTP 服务器来执行发送电子邮件的过程。SMTP服务器则是按照这些规则中转电子邮件的服务器。 IMAP…

Java web应用性能分析之【MySQL安装注意事项】

本文主要是针对以前LAMP&#xff0c;以及默认用apt安装的mysql。数据文件、日志文件都在一起&#xff1b;innodb_buffer_pool默认用128M。如果你排查问题&#xff0c;最后发现是因为mysql的安装配置不对&#xff0c;是否一口老血要喷出来。同时给MySQL数据库安装做参考。 关于M…