c语言练手项目【编写天天酷跑游戏2.0】EASYX图形库的运用。代码开源,素材已打包

天天酷跑项目的开发

项目前言

项目是基于Windows,easyX图形库进行开发的,

开发环境:Visual Studio 2022

项目技术最低要求:

常量,变量,数组,循环,函数。
在这里插入图片描述

文章目录

  • 天天酷跑项目的开发
    • 项目前言
    • 游戏背景的实现
    • 实现玩家的奔跑
    • 实现人物的跳跃
      • 获取玩家的输入
    • 优化帧等待
    • 随机出现小乌龟障碍
    • 使用结构体优化障碍
      • 使用结构体后,重新初始化游戏
    • 实现下蹲技能
    • 添加柱子障碍物
    • 碰撞检测
    • 实现血条
    • 判断游戏结束 添加背景音乐 添加初始界面
    • 优化死亡BUG
    • 跨越障碍后计算得分
    • 判断游戏胜利
    • 源代码

游戏背景的实现

  • 使用initgraph()初始化界面;
  • 加载背景资源

写好游戏的图像化界面的框架

在这里插入图片描述

由于easyX不支持透明图片的的贴图,所以我们要自己写一个透明贴图的函数这里给出3个

// 适用于 y <0 以及y>0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture);
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture);
void putimagePNG(int  picture_x, int picture_y, IMAGE* picture);
// 适用于 y <0 以及x<0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture) {IMAGE imgTmp;if (y < 0) {SetWorkingImage(picture);getimage(&imgTmp, 0, -y,picture->getwidth(), picture->getheight() + y);SetWorkingImage();y = 0;picture = &imgTmp;}if (x < 0) {SetWorkingImage(picture);getimage(&imgTmp, -x, 0, picture->getwidth() + x, picture->getheight());SetWorkingImage();x = 0;picture = &imgTmp;}putimagePNG(x, y, picture);
}// 适用于 y <0 以及y>0的任何情况
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture) {IMAGE imgTmp;if (y < 0) {SetWorkingImage(picture);getimage(&imgTmp, 0, -y,picture->getwidth(), picture->getheight() + y);SetWorkingImage();y = 0;picture = &imgTmp;}if (x < 0) {SetWorkingImage(picture);getimage(&imgTmp, -x, 0, picture->getwidth() + x, picture->getheight());SetWorkingImage();x = 0;picture = &imgTmp;}else if (x >= winWidth) {return;}else if (x > winWidth - picture->getwidth()) {SetWorkingImage(picture);getimage(&imgTmp, 0, 0, winWidth - x, picture->getheight());SetWorkingImage();picture = &imgTmp;}putimagePNG(x, y, picture);
}// 载入PNG图并去透明部分
void putimagePNG(int  picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
{DWORD* dst = GetImageBuffer();    // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带DWORD* draw = GetImageBuffer();DWORD* src = GetImageBuffer(picture); //获取picture的显存指针int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带int picture_height = picture->getheight(); //获取picture的高度,EASYX自带int graphWidth = getwidth();       //获取绘图区的宽度,EASYX自带int graphHeight = getheight();     //获取绘图区的高度,EASYX自带int dstX = 0;    //在显存里像素的角标// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算for (int iy = 0; iy < picture_height; iy++){for (int ix = 0; ix < picture_width; ix++){int srcX = ix + iy * picture_width; //在显存里像素的角标int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的Rint sg = ((src[srcX] & 0xff00) >> 8);   //Gint sb = src[srcX] & 0xff;              //Bif (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight){dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标int dr = ((dst[dstX] & 0xff0000) >> 16);int dg = ((dst[dstX] & 0xff00) >> 8);int db = dst[dstX] & 0xff;draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)  //公式: Cp=αp*FP+(1-αp)*BP  ; αp=sa/255 , FP=sr , BP=dr| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)         //αp=sa/255 , FP=sg , BP=dg| (sb * sa / 255 + db * (255 - sa) / 255);              //αp=sa/255 , FP=sb , BP=db}}}
}
//定义相关的变量
IMAGE imgBgs[3]; // 背景图片
int bgX[3];  //背景图片的x坐标
int bgSpeed[3] = { 1, 2, 4 };//三重背景以不同速度行驶

三张背景图片需要载入

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//直接在初始化中加载到内存char name[64];for (int i = 0; i < 3; i++) {// "res/bg001.png"    "res/bg002.png"     "res/bg003.png"   sprintf(name, "res/bg%03d.png", i + 1);loadimage(&imgBgs[i], name);bgX[i] = 0;}

注:这里的图片在main.cpp文件夹中的res文件夹下。

再在updateBg的函数中进行渲染;

  	putimagePNG2(bgX[0], 0, &imgBgs[0]);putimagePNG2(bgX[1], 119, &imgBgs[1]);putimagePNG2(bgX[2], 330, &imgBgs[2]);

编译如果遇到C4996错误只需要在项目属性c/c++中关掉SDL检查即可。

如果出现loadimage()的错误,可能是字符集的问题;只需要在项目属性-高级-字符集-使用多字节字符集即可

看一下执行结果。

在这里插入图片描述

如果不使用透明贴图函数

在这里插入图片描述

图片成功渲染,但是在实际的游戏中,背景是会移动的且遵守基本的物理。

接下来我们需要移动背景。远处的移动慢,中处更快,最近处看起来最快,所以速度可以取int bgSpeed[3] = { 1, 2, 4 };

void moveBg() {for (int i = 0; i < 3; i++) {bgX[i] -= bgSpeed[i];if (bgX[i] < -WIN_WIDTH) {bgX[i] = 0;}}

在main函数中载入死循环 这样背景就可以无休止的移动了

int main(void) {init();while (1) {BeginBatchDraw();updateBg();EndBatchDraw();moveBg();Sleep(30);}
//使用beginbatchdraw 和endbatchdraw进行优化渲染。}

实现玩家的奔跑

IMAGE imgHeros[12];//玩家的帧图片
int heroX; //玩家的x坐标
int heroY; //玩家的y坐标
int heroIndex; //玩家奔跑的图片帧序号

在这里插入图片描述

初始化的时候也初始化玩家

    // 加载Hero奔跑的图片帧素材for (int i = 0; i < 12; i++) {// "res/hero1.png"  ... "res/hero12.png"sprintf(name, "res/hero%d.png", i + 1);loadimage(&imgHeros[i], name);}
// 设置玩家的初始位置heroX = WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;heroY = 345 - imgHeros[0].getheight();heroIndex = 0;

在Main函数中给hero贴图

   putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);

在这里插入图片描述

更改人物帧图片,让人物看起来会动

  heroIndex = (heroIndex + 1) % 12;

在这里插入图片描述

RUN:

在这里插入图片描述

实现人物的跳跃

初始化函数中

在这里插入图片描述

heroJump = false;
jumpHeightMax = 345 - imgHeros[0].getheight() - 120;
heroJumpOff = -4;
bool heroJump; //表示玩家正在跳跃
int jumpHeightMax;
int heroJumpOff;

在这里插入图片描述

int jump()
{// 实现跳跃if (heroJump) {if (heroY < jumpHeightMax) {heroJumpOff = 4;}heroY += heroJumpOff;if (heroY > 345 - imgHeros[0].getheight()) {heroJump = false;heroJumpOff = -4;}}else { //不跳跃heroIndex = (heroIndex + 1) % 12;}
}
void jump() {heroJump = true;
}

获取玩家的输入

// 处理用户按键的输入
void keyEvent() {char ch;if (_kbhit()) { //如果有按键按下,_kbhit()返回  true  ch = _getch();    // _getch()不需要按下回车即可直接读取if (ch == ' ') {jump();}} 
}

main()

int main(void) {init();while (1) {keyEvent();BeginBatchDraw();updateBg();putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);EndBatchDraw();moveBg();HeroIndex();jump(heroJump);Sleep(15);}}

在这里插入图片描述

优化帧等待

bool update;   //表示是否需要马上刷新画面

init()尾部

update = true;

void jump() {heroJump = true;update = true;
}
int getDelay() {static unsigned long long lastTime = 0;unsigned long long currentTime = GetTickCount();if (lastTime == 0) {lastTime = currentTime;return 0;}else {int ret = currentTime - lastTime;lastTime = currentTime;return ret;}
}

main函数主体

int main(void) {int timer = 0;init();while (1) {keyEvent();timer += getDelay();//10if (timer > 30) {timer = 0;update = true;}if (update){update = false;BeginBatchDraw();updateBg();putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);EndBatchDraw();moveBg();HeroIndex();jump(heroJump);} }return 0;
}

随机出现小乌龟障碍

定义乌龟相关的变量

IMAGE imgTortoise; //小乌龟
int torToiseX; //小乌龟的水平坐标
int torToiseY; //小乌龟的垂直坐标
bool torToiseExist; //当前窗口是否有小乌龟

在init()函数中,初始化乌龟

    // 加载小乌龟素材loadimage(&imgTortoise, "res/t1.png");torToiseExist = false;torToiseY = 345 - imgTortoise.getheight() + 5;

定义一个函数创建小乌龟

void creatTortoise() {// 创建小乌龟static int frameCount = 0;static int torToiseFre = 100;frameCount++;if (frameCount > torToiseFre) {frameCount = 0;if (!torToiseExist) {torToiseExist = true;torToiseX = WIN_WIDTH;torToiseFre = 200 + rand() % 300;}}if (torToiseExist) {torToiseX -= bgSpeed[2];if (torToiseX < -imgTortoise.getwidth()) {torToiseExist = false;}}
}

创建函数对乌龟进行渲染

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

再把creattortorise

在这里插入图片描述

在main函数中调用if语句中

    update = false;BeginBatchDraw();updateBg();putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);updateEnemy();EndBatchDraw();moveBg();HeroIndex();creatTortoise();jump(heroJump);

使用结构体优化障碍

添加头文件\#include <vector>

#define OBSTACLE_COUNT 10
typedef enum {TORTOISE, //乌龟  0LION, //狮子 1OBSTACLE_TYPE_COUNT  // 2
} obstacle_type;vector<vector<IMAGE>>obstacleImgs; //存放所有障碍物的各个图片typedef struct obstacle {obstacle_type type; //障碍物的类型 int imgIndex; //当前显示的图片的序号int x, y; //障碍物的坐标int speed;int power; //杀伤力bool exist;
}obstacle_t;

使用结构体后,重新初始化游戏

obstacle_t obstacles[OBSTACLE_COUNT];

// 游戏的初始化
void init() {// 创建游戏窗口initgraph(WIN_WIDTH, WIN_HEIGHT);// 加载背景资源char name[64];for (int i = 0; i < 3; i++) {// "res/bg001.png"    "res/bg002.png"     "res/bg003.png"   sprintf(name, "res/bg%03d.png", i + 1);loadimage(&imgBgs[i], name);bgX[i] = 0;}// 加载Hero奔跑的图片帧素材for (int i = 0; i < 12; i++) {// "res/hero1.png"  ... "res/hero12.png"sprintf(name, "res/hero%d.png", i + 1);loadimage(&imgHeros[i], name);}// 设置玩家的初始位置heroX = WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;heroY = 345 - imgHeros[0].getheight();heroIndex = 0;heroJump = false;jumpHeightMax = 345 - imgHeros[0].getheight() - 120;heroJumpOff = -4;update = true;IMAGE imgTort;loadimage(&imgTort, "res/t1.png");vector<IMAGE> imgTortArray;imgTortArray.push_back(imgTort);obstacleImgs.push_back(imgTortArray);IMAGE imgLion;vector<IMAGE> imgLionArray;for (int i = 0; i < 6; i++) {sprintf(name, "res/p%d.png", i + 1);loadimage(&imgLion, name);imgLionArray.push_back(imgLion);}obstacleImgs.push_back(imgLionArray);// 初始化障碍物池for (int i = 0; i < OBSTACLE_COUNT; i++) {obstacles[i].exist = false;}
}

创建函数初始化障碍物(我们将用此函数创建所有的障碍物)

void createObstacle() {int i;for (i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist == false) {break;}}if (i >= OBSTACLE_COUNT) {return;}obstacles[i].exist = true;obstacles[i].imgIndex = 0;obstacles[i].type = (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);obstacles[i].x = WIN_WIDTH;obstacles[i].y = 345 + 5 - obstacleImgs[obstacles[i].type][0].getheight();if (obstacles[i].type == TORTOISE) {obstacles[i].speed = 0;obstacles[i].power = 5; //自己修改}else if (obstacles[i].type == LION) {obstacles[i].speed = 4;obstacles[i].power = 20;}
}

再写一个函数进行创建障碍物的数据计算

void createObstacleData() {static int frameCount = 0;static int enemyFre = 50;frameCount++;if (frameCount > enemyFre) {frameCount = 0;enemyFre = 50 + rand() % 50; // 50..99createObstacle();}// 更新所有障碍物的坐标for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist) {obstacles[i].x -= obstacles[i].speed + bgSpeed[2];if (obstacles[i].x < -obstacleImgs[obstacles[i].type][0].getwidth() * 2) {obstacles[i].exist = false;}int len = obstacleImgs[obstacles[i].type].size();obstacles[i].imgIndex = (obstacles[i].imgIndex + 1) % len;}}
}

在对敌人初始化

void updateEnemy() {// 渲染小乌龟//if (torToiseExist) {//    putimagePNG2(torToiseX, torToiseY, WIN_WIDTH, &imgTortoise);//}for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist) {putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH,&obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]);}}
}

一下是main函数的主体

		if (update){update = false;BeginBatchDraw();updateBg();putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);updateEnemy();EndBatchDraw();updateEnemy();moveBg();HeroIndex();createObstacleData();jump(heroJump);}

实现下蹲技能

IMAGE imgHeroDown[2];
bool heroDown; //表示玩家是否处于下蹲状态

init()中对其初始化

// 初始化障碍物池for (int i = 0; i < OBSTACLE_COUNT; i++) {obstacles[i].exist = false;}// 加载下蹲素材loadimage(&imgHeroDown[0], "res/d1.png");loadimage(&imgHeroDown[1], "res/d2.png");heroDown = false;

我们写一个heroupdown函数集成up和down方便进行管理

void heroupdown()
{// 实现跳跃if (heroJump) {if (heroY < jumpHeightMax) {heroJumpOff = 4;}heroY += heroJumpOff;if (heroY > 345 - imgHeros[0].getheight()) {heroJump = false;heroJumpOff = -4;}}else if (heroDown) {static int count = 0;int delays[2] = { 4, 10 };count++;if (count >= delays[heroIndex]) {count = 0;heroIndex++;if (heroIndex >= 2) {heroIndex = 0;heroDown = false;}}}else { //不跳跃heroIndex = (heroIndex + 1) % 12;}
}
void down() {update = true;heroDown = true;heroIndex = 0;
}

在接受键盘进行响应

void keyEvent() {char ch;if (_kbhit()) { //如果有按键按下,_kbhit()返回  true  ch = _getch();    // _getch()不需要按下回车即可直接读取if (ch == ' ') {jump();}else if (ch == 'a') {down();}}
}
void updateHero() {if (!heroDown) {putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);}else {int y = 345 - imgHeroDown[heroIndex].getheight();putimagePNG2(heroX, y, &imgHeroDown[heroIndex]);}}

main函数主体

int main(void) {int timer = 0;init();while (1) {keyEvent();timer += getDelay();//10if (timer > 20) {timer = 0;update = true;}if (update){update = false;BeginBatchDraw();updateBg();//putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);updateHero(); updateEnemy();EndBatchDraw();moveBg();heroupdown();createObstacleData();}}return 0;
}

添加柱子障碍物

老规矩 加载-初始化

typedef enum {TORTOISE, //乌龟  0LION, //狮子 1OBSTACLE_TYPE_COUNT  // 2HOOK1,      //勾子HOOK2,HOOK3,HOOK4,
} obstacle_type;
void createObstacle() {srand((unsigned)time(NULL));int i;for (i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist == false) {break;}}if (i >= OBSTACLE_COUNT) {return;}obstacles[i].exist = true;obstacles[i].imgIndex = 0;//obstacles[i].type = (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);obstacles[i].type = (obstacle_type)(rand() % 3);obstacles[i].x = WIN_WIDTH;obstacles[i].y = 345 + 5 - obstacleImgs[obstacles[i].type][0].getheight();if (obstacles[i].type == HOOK1) {obstacles[i].type = (obstacle_type)((int)(obstacles[i].type) + rand() % 4);}if (obstacles[i].type == TORTOISE) {obstacles[i].speed = 0;obstacles[i].power = 5; //自己修改}else if (obstacles[i].type == LION) {obstacles[i].speed = 4;obstacles[i].power = 20;}else if (obstacles[i].type >= HOOK1 && obstacles[i].type <= HOOK4) {obstacles[i].speed = 0;obstacles[i].power = 20;obstacles[i].y = 0;}}

碰撞检测

typedef struct obstacle {obstacle_type type; //障碍物的类型int imgIndex; //当前显示的图片的序号int x, y; //障碍物的坐标int speed;int power; //杀伤力bool exist;bool hited;//是否撞击
}obstacle_t;
void  preLoadSound(const char* name) {char cmd[512];sprintf_s(cmd, sizeof(cmd), "open %s alias %s-1", name, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), "open %s alias %s-2", name, name);mciSendString(cmd, 0, 0, 0);
}
bool rectIntersect(int x01, int y01, int x02, int y02,int x11, int y11, int x12, int y12)
{int zx = abs(x01 + x02 - x11 - x12);int x = abs(x01 - x02) + abs(x11 - x12);int zy = abs(y01 + y02 - y11 - y12);int y = abs(y01 - y02) + abs(y11 - y12);return  (zx <= x && zy <= y);
}
void  playSound(const char* name) {static int index = 1;char cmd[512];if (index == 1) {sprintf_s(cmd, sizeof(cmd), "play %s-1", name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), "close %s-2", name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), "open %s alias %s-2", name, name);mciSendString(cmd, 0, 0, 0);index++;}else if (index == 2) {sprintf_s(cmd, sizeof(cmd), "play %s-2", name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), "close %s-1", name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), "open %s alias %s-1", name, name);mciSendString(cmd, 0, 0, 0);index = 1;}
}
void checkHit()
{for (int i = 0; i < OBSTACLE_COUNT; i++){if (obstacles[i].exist && obstacles[i].hited == false){int a1x, a1y, a2x, a2y;int off = 20;if (!heroDown)//非下蹲 奔跑 跳跃{a1x = heroX + off;a1y = heroY + off;a2x = heroX + imgHeros[heroIndex].getwidth() - off;a2y = heroY + imgHeros[heroIndex].getheight();}else { //下蹲状态a1x = heroX + off;a1y = 345 - imgHeroDown[heroIndex].getheight();a2x = heroX + imgHeroDown[heroIndex].getwidth() - off;a2y = 345;}IMAGE img = obstacleImgs[obstacles[i].type][obstacles[i].imgIndex];int b1x = obstacles[i].x + off;int b1y = obstacles[i].y + off;int b2x = obstacles[i].x + img.getwidth() - off;int b2y = obstacles[i].y + img.getheight() - 10;if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)){heroBlood -= obstacles[i].power;playSound("res/hit.mp3");obstacles[i].hited = true;}}}}

在这里插入图片描述

实现血条

优化下蹲:

int delays[2] = { 6, 10 };

改成
int delays[2] = { 8, 30 };

头文件

#include <mmsystem.h>
#pragma comment(lib, “winmm.lib”)

void updateBloodBar() {drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0);
}

void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent) {LINESTYLE lineStyle;getlinestyle(&lineStyle);int lineColor = getlinecolor();int fileColor = getfillcolor();if (percent < 0) {percent = 0;}setlinecolor(BLUE);setlinestyle(PS_SOLID | PS_ENDCAP_ROUND, lineWidth);setfillcolor(emptyColor);fillrectangle(x, y, x + width, y + height);setlinestyle(PS_SOLID | PS_ENDCAP_FLAT, 0);setfillcolor(fillColor);setlinecolor(fillColor);if (percent > 0) {fillrectangle(x + 0.5 * lineWidth, y + lineWidth * 0.5, x + width * percent, y + height - 0.5 * lineWidth);}setlinecolor(lineColor);setfillcolor(fillColor);setlinestyle(&lineStyle);
}
void init() {// 创建游戏窗口initgraph(WIN_WIDTH, WIN_HEIGHT);// 加载背景资源char name[64];for (int i = 0; i < 3; i++) {// "res/bg001.png"    "res/bg002.png"     "res/bg003.png"   sprintf(name, "res/bg%03d.png", i + 1);loadimage(&imgBgs[i], name);bgX[i] = 0;}// 加载Hero奔跑的图片帧素材for (int i = 0; i < 12; i++) {// "res/hero1.png"  ... "res/hero12.png"sprintf(name, "res/hero%d.png", i + 1);loadimage(&imgHeros[i], name);}// 设置玩家的初始位置heroX = WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;heroY = 345 - imgHeros[0].getheight();heroIndex = 0;heroJump = false;jumpHeightMax = 345 - imgHeros[0].getheight() - 120;heroJumpOff = -4;update = true;IMAGE imgTort;loadimage(&imgTort, "res/t1.png");vector<IMAGE> imgTortArray;imgTortArray.push_back(imgTort);obstacleImgs.push_back(imgTortArray);IMAGE imgLion;vector<IMAGE> imgLionArray;for (int i = 0; i < 6; i++) {sprintf(name, "res/p%d.png", i + 1);loadimage(&imgLion, name);imgLionArray.push_back(imgLion);}obstacleImgs.push_back(imgLionArray);// 初始化障碍物池for (int i = 0; i < OBSTACLE_COUNT; i++) {obstacles[i].exist = false;}// 加载下蹲素材loadimage(&imgHeroDown[0], "res/d1.png");loadimage(&imgHeroDown[1], "res/d2.png");heroDown = false;// 加载“柱子”障碍物IMAGE imgH;vector<IMAGE> imgHookArray;for (int i = 0; i < 4; i++) {sprintf_s(name, sizeof(name), "res/h%d.png", i + 1); //帧图片不够,补帧loadimage(&imgH, name, 63, 260, true);imgHookArray.push_back(imgH);obstacleImgs.push_back(imgHookArray);imgHookArray.pop_back();}heroBlood = 100;// 预加载音效preLoadSound("res/hit.mp3");}

main : updateBloodBar();

判断游戏结束 添加背景音乐 添加初始界面

用屁股想 是初始化函数中

    mciSendString("play res/bg.mp3", 0, 0, 0);

在这里插入图片描述

    if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {heroBlood -= obstacles[i].power;printf("血量剩余 %d\n", heroBlood);playSound("res/hit.mp3");obstacles[i].hited = true;}
void checkOver() {if (heroBlood <= 0) {loadimage(0, "res/over.png");FlushBatchDraw();mciSendString("stop res/bg.mp3", 0, 0, 0);system("pause");// 暂停之后,充币复活,或者直接开始下一局heroBlood = 100;mciSendString("play res/bg.mp3", 0, 0, 0);}
}
int main(void) {int timer = 0;init();// 显示初始画面loadimage(0, "res/over.png");system("pause");while (1) {keyEvent();timer += getDelay();//10if (timer > 20) {timer = 0;update = true;}if (update){update = false;BeginBatchDraw();updateBg();updateHero(); updateEnemy();updateBloodBar();EndBatchDraw();moveBg();heroupdown();createObstacleData();checkHit();checkOver();}}return 0;
}

优化死亡BUG

int lastObsIndex; //last obstacle index
void createObstacle() {srand((unsigned)time(NULL));int i;for (i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist == false) {break;}}if (i >= OBSTACLE_COUNT) {return;}obstacles[i].exist = true;obstacles[i].imgIndex = 0;//obstacles[i].type = (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);obstacles[i].type = (obstacle_type)(rand() % 3);obstacles[i].x = WIN_WIDTH;obstacles[i].y = 345 + 5 - obstacleImgs[obstacles[i].type][0].getheight();if (lastObsIndex >= HOOK1 && lastObsIndex <= HOOK4 &&obstacles[i].type == LION &&obstacles[lastObsIndex].x > (WIN_WIDTH - 500)) {obstacles[i].type = TORTOISE;}lastObsIndex = i;if (obstacles[i].type == HOOK1) {obstacles[i].type = (obstacle_type)((int)(obstacles[i].type) + rand() % 4);}if (obstacles[i].type == TORTOISE) {obstacles[i].speed = 0;obstacles[i].power = 5; //自己修改}else if (obstacles[i].type == LION) {obstacles[i].speed = 4;obstacles[i].power = 20;}else if (obstacles[i].type >= HOOK1 && obstacles[i].type <= HOOK4) {obstacles[i].speed = 0;obstacles[i].power = 20;obstacles[i].y = 0;}}

跨越障碍后计算得分

int score; //分数
lastObsIndex = -1;score = 0;
void checkScore() {for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist &&obstacles[i].passed == false &&obstacles[i].x + obstacleImgs[obstacles[i].type][0].getwidth() < heroX) {score++;obstacles[i].passed = true;printf("score: %d\n", score);}}
}
typedef struct obstacle {obstacle_type type; //障碍物的类型int imgIndex; //当前显示的图片的序号int x, y; //障碍物的坐标int speed;int power; //杀伤力bool exist;bool hited;bool passed;
}obstacle_t;
int main(void) {int timer = 0;init();// 显示初始画面loadimage(0, "res/over.png");system("pause");while (1) {keyEvent();timer += getDelay();//10if (timer > 20) {timer = 0;update = true;}if (update){update = false;BeginBatchDraw();updateBg();updateHero(); updateEnemy();updateBloodBar();EndBatchDraw();moveBg();heroupdown();createObstacleData();checkHit();checkOver();checkScore();}}return 0;
}
void updateScore() {// 50 => "50"   '5'     '5'-'0' == 5   char str[8];sprintf(str, "%d", score);int x = 20;int y = 25;for (int i = 0; str[i]; i++) {int sz = str[i] - '0';putimagePNG(x, y, &imgSZ[sz]);x += imgSZ[sz].getwidth() + 5;}
}
 		   updateBloodBar();updateScore();EndBatchDraw();checkOver();checkScore();

判断游戏胜利

写main函数中的位置 这里不再赘述

#define WIN_SCORE   100
void checkWin() {if (score >= WIN_SCORE) {FlushBatchDraw();mciSendString("play res/win.mp3", 0, 0, 0);Sleep(2000);loadimage(0, "res/win.png");FlushBatchDraw();mciSendString("stop res/bg.mp3", 0, 0, 0);system("pause");heroBlood = 100;score = 0;mciSendString("play res/bg.mp3 repeat", 0, 0, 0);}
}

源代码

#include <stdio.h>
#include <graphics.h>
#include <conio.h>
#include <vector>
#include <time.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")#define WIN_SCORE   100
#define WIN_WIDTH 1012
#define WIN_HEIGHT 396
#define OBSTACLE_COUNT 10using namespace std;IMAGE imgHeros[12];
IMAGE imgBgs[3];
IMAGE imgHeroDown[2];
int bgX[3]; 
int bgSpeed[3] = { 1, 2, 4 };
int heroX;
int heroY;
int heroIndex;
bool heroJump;
int jumpHeightMax;
int heroJumpOff;
bool update;
bool heroDown; 
int heroBlood;
int score;
int lastObsIndex;typedef enum {TORTOISE, //乌龟  0LION, //狮子 1	 HOOK1,      //勾子HOOK2,HOOK3,HOOK4,OBSTACLE_TYPE_COUNT ,
} obstacle_type;vector<vector<IMAGE>>obstacleImgs; //存放所有障碍物的各个图片typedef struct obstacle {obstacle_type type; //障碍物的类型int imgIndex; //当前显示的图片的序号int x, y; //障碍物的坐标int speed;int power; //杀伤力bool exist;bool hited;bool passed;
}obstacle_t;obstacle_t obstacles[OBSTACLE_COUNT];void  preLoadSound(const char* name);
void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent);void init();
void moveBg();
void jump();
void heroupdown();
int getDelay();
void keyEvent();
void updateBg();
void updateEnemy();
void jump(bool herJump);
bool rectIntersect(int a1X, int a1Y, int a2X, int a2Y,int b1X, int b1Y, int b2X, int b2Y);
void updateEnemy();
void updateBloodBar();
void createObstacleData();
void createObstacle();void putimagePNG2(int x, int y, IMAGE* picture);
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture);
void putimagePNG(int  picture_x, int picture_y, IMAGE* picture);
void HeroIndex();
void  playSound(const char* name);void  preLoadSound(const char* name) {char cmd[512];sprintf_s(cmd, sizeof(cmd), "open %s alias %s-1", name, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), "open %s alias %s-2", name, name);mciSendString(cmd, 0, 0, 0);
}void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent) {LINESTYLE lineStyle;getlinestyle(&lineStyle);int lineColor = getlinecolor();int fileColor = getfillcolor();if (percent < 0) {percent = 0;}setlinecolor(BLUE);setlinestyle(PS_SOLID | PS_ENDCAP_ROUND, lineWidth);setfillcolor(emptyColor);fillrectangle(x, y, x + width, y + height);setlinestyle(PS_SOLID | PS_ENDCAP_FLAT, 0);setfillcolor(fillColor);setlinecolor(fillColor);if (percent > 0) {fillrectangle(x + 0.5 * lineWidth, y + lineWidth * 0.5, x + width * percent, y + height - 0.5 * lineWidth);}setlinecolor(lineColor);setfillcolor(fillColor);setlinestyle(&lineStyle);
}bool rectIntersect(int x01, int y01, int x02, int y02,int x11, int y11, int x12, int y12)
{int zx = abs(x01 + x02 - x11 - x12);int x = abs(x01 - x02) + abs(x11 - x12);int zy = abs(y01 + y02 - y11 - y12);int y = abs(y01 - y02) + abs(y11 - y12);return  (zx <= x && zy <= y);
}void  playSound(const char* name) {static int index = 1;char cmd[512];if (index == 1) {sprintf_s(cmd, sizeof(cmd), "play %s-1", name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), "close %s-2", name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), "open %s alias %s-2", name, name);mciSendString(cmd, 0, 0, 0);index++;}else if (index == 2) {sprintf_s(cmd, sizeof(cmd), "play %s-2", name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), "close %s-1", name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), "open %s alias %s-1", name, name);mciSendString(cmd, 0, 0, 0);index = 1;}
}void putimagePNG(int  picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
{DWORD* dst = GetImageBuffer();    // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带DWORD* draw = GetImageBuffer();DWORD* src = GetImageBuffer(picture); //获取picture的显存指针int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带int picture_height = picture->getheight(); //获取picture的高度,EASYX自带int graphWidth = getwidth();       //获取绘图区的宽度,EASYX自带int graphHeight = getheight();     //获取绘图区的高度,EASYX自带int dstX = 0;    //在显存里像素的角标// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算for (int iy = 0; iy < picture_height; iy++){for (int ix = 0; ix < picture_width; ix++){int srcX = ix + iy * picture_width; //在显存里像素的角标int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的Rint sg = ((src[srcX] & 0xff00) >> 8);   //Gint sb = src[srcX] & 0xff;              //Bif (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight){dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标int dr = ((dst[dstX] & 0xff0000) >> 16);int dg = ((dst[dstX] & 0xff00) >> 8);int db = dst[dstX] & 0xff;draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)  //公式: Cp=αp*FP+(1-αp)*BP  ; αp=sa/255 , FP=sr , BP=dr| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)         //αp=sa/255 , FP=sg , BP=dg| (sb * sa / 255 + db * (255 - sa) / 255);              //αp=sa/255 , FP=sb , BP=db}}}
}// 适用于 y <0 以及x<0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture) {IMAGE imgTmp;if (y < 0) {SetWorkingImage(picture);getimage(&imgTmp, 0, -y,picture->getwidth(), picture->getheight() + y);SetWorkingImage();y = 0;picture = &imgTmp;}if (x < 0) {SetWorkingImage(picture);getimage(&imgTmp, -x, 0, picture->getwidth() + x, picture->getheight());SetWorkingImage();x = 0;picture = &imgTmp;}putimagePNG(x, y, picture);
}// 适用于 y <0 以及y>0的任何情况
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture) {IMAGE imgTmp;if (y < 0) {SetWorkingImage(picture);getimage(&imgTmp, 0, -y,picture->getwidth(), picture->getheight() + y);SetWorkingImage();y = 0;picture = &imgTmp;}if (x < 0) {SetWorkingImage(picture);getimage(&imgTmp, -x, 0, picture->getwidth() + x, picture->getheight());SetWorkingImage();x = 0;picture = &imgTmp;}else if (x >= winWidth) {return;}else if (x > winWidth - picture->getwidth()) {SetWorkingImage(picture);getimage(&imgTmp, 0, 0, winWidth - x, picture->getheight());SetWorkingImage();picture = &imgTmp;}putimagePNG(x, y, picture);
}void jump() {heroJump = true;update = true;
}void down() {update = true;heroDown = true;heroIndex = 0;
}void heroupdown()
{// 实现跳跃if (heroJump) {if (heroY < jumpHeightMax) {heroJumpOff = 4;}heroY += heroJumpOff;if (heroY > 345 - imgHeros[0].getheight()) {heroJump = false;heroJumpOff = -4;}}else if (heroDown) {static int count = 0;int delays[2] = { 8, 30 };count++;if (count >= delays[heroIndex]) {count = 0;heroIndex++;if (heroIndex >= 2) {heroIndex = 0;heroDown = false;}}}else { //不跳跃heroIndex = (heroIndex + 1) % 12;}
}void updateBloodBar() {drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0);
}
void moveBg() {for (int i = 0; i < 3; i++) {bgX[i] -= bgSpeed[i];if (bgX[i] < -WIN_WIDTH) {bgX[i] = 0;}}
}void createObstacleData() {static int frameCount = 0;static int enemyFre = 50;frameCount++;if (frameCount > enemyFre) {frameCount = 0;enemyFre = 50 + rand() % 50; // 50..99createObstacle();}// 更新所有障碍物的坐标for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist) {obstacles[i].x -= obstacles[i].speed + bgSpeed[2];if (obstacles[i].x < -obstacleImgs[obstacles[i].type][0].getwidth() * 2) {obstacles[i].exist = false;}int len = obstacleImgs[obstacles[i].type].size();obstacles[i].imgIndex = (obstacles[i].imgIndex + 1) % len;}}
}
void checkHit()
{for (int i = 0; i < OBSTACLE_COUNT; i++){if (obstacles[i].exist && obstacles[i].hited == false){int a1x, a1y, a2x, a2y;int off = 20;if (!heroDown)//非下蹲 奔跑 跳跃{a1x = heroX + off;a1y = heroY + off;a2x = heroX + imgHeros[heroIndex].getwidth() - off;a2y = heroY + imgHeros[heroIndex].getheight();}else { //下蹲状态a1x = heroX + off;a1y = 345 - imgHeroDown[heroIndex].getheight();a2x = heroX + imgHeroDown[heroIndex].getwidth() - off;a2y = 345;}IMAGE img = obstacleImgs[obstacles[i].type][obstacles[i].imgIndex];int b1x = obstacles[i].x + off;int b1y = obstacles[i].y + off;int b2x = obstacles[i].x + img.getwidth() - off;int b2y = obstacles[i].y + img.getheight() - 10;if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {heroBlood -= obstacles[i].power;printf("血量剩余 %d\n", heroBlood);playSound("res/hit.mp3");obstacles[i].hited = true;}}}}void checkOver() {if (heroBlood <= 0) {loadimage(0, "res/over.png");FlushBatchDraw();mciSendString("stop res/bg.mp3", 0, 0, 0);system("pause");// 暂停之后,充币复活,或者直接开始下一局heroBlood = 100;mciSendString("play res/bg.mp3", 0, 0, 0);}
}void createObstacle() {srand((unsigned)time(NULL));int i;for (i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist == false) {break;}}if (i >= OBSTACLE_COUNT) {return;}obstacles[i].exist = true;obstacles[i].imgIndex = 0;//obstacles[i].type = (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);obstacles[i].type = (obstacle_type)(rand() % 3);obstacles[i].x = WIN_WIDTH;obstacles[i].y = 345 + 5 - obstacleImgs[obstacles[i].type][0].getheight();if (lastObsIndex >= HOOK1 && lastObsIndex <= HOOK4 &&obstacles[i].type == LION &&obstacles[lastObsIndex].x > (WIN_WIDTH - 500)) {obstacles[i].type = TORTOISE;}lastObsIndex = i;if (obstacles[i].type == HOOK1) {obstacles[i].type = (obstacle_type)((int)(obstacles[i].type) + rand() % 4);}if (obstacles[i].type == TORTOISE) {obstacles[i].speed = 0;obstacles[i].power = 5; //自己修改}else if (obstacles[i].type == LION) {obstacles[i].speed = 4;obstacles[i].power = 20;}else if (obstacles[i].type >= HOOK1 && obstacles[i].type <= HOOK4) {obstacles[i].speed = 0;obstacles[i].power = 20;obstacles[i].y = 0;}}//渲染游戏背景
void updateBg()
{putimagePNG2(bgX[0], 0, &imgBgs[0]);putimagePNG2(bgX[1], 119, &imgBgs[1]);putimagePNG2(bgX[2], 330, &imgBgs[2]);
}
//处理用户按键的输入
//void keyEvent() {
//	char ch;
//
//	if (_kbhit()) { //如果有按键按下,_kbhit()返回  true
//		ch = _getch();    // _getch()不需要按下回车即可直接读取
//		if (ch == ' ') {
//			jump();
//		}
//	}
//}// 处理用户按键的输入
void keyEvent() {char ch;if (_kbhit()) { //如果有按键按下,_kbhit()返回  true  ch = _getch();    // _getch()不需要按下回车即可直接读取if (ch == ' ') {jump();}else if (ch == 's') {down();}}
}void jump(bool heroJump)
{// 实现跳跃if (heroJump) {if (heroY < jumpHeightMax) {heroJumpOff = 4;}heroY += heroJumpOff;if (heroY > 345 - imgHeros[0].getheight()) {heroJump = false;heroJumpOff = -4;}}else { //不跳跃heroIndex = (heroIndex + 1) % 12;}update = true;
}void updateEnemy() {for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist) {putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH,&obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]);}}
}
// 游戏的初始化
void init() {// 创建游戏窗口initgraph(WIN_WIDTH, WIN_HEIGHT);// 加载背景资源char name[64];for (int i = 0; i < 3; i++) {// "res/bg001.png"    "res/bg002.png"     "res/bg003.png"   sprintf(name, "res/bg%03d.png", i + 1);loadimage(&imgBgs[i], name);bgX[i] = 0;}// 加载Hero奔跑的图片帧素材for (int i = 0; i < 12; i++) {// "res/hero1.png"  ... "res/hero12.png"sprintf(name, "res/hero%d.png", i + 1);loadimage(&imgHeros[i], name);}// 设置玩家的初始位置heroX = WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;heroY = 345 - imgHeros[0].getheight();heroIndex = 0;heroJump = false;jumpHeightMax = 345 - imgHeros[0].getheight() - 120;heroJumpOff = -4;update = true;IMAGE imgTort;loadimage(&imgTort, "res/t1.png");vector<IMAGE> imgTortArray;imgTortArray.push_back(imgTort);obstacleImgs.push_back(imgTortArray);IMAGE imgLion;vector<IMAGE> imgLionArray;for (int i = 0; i < 6; i++) {sprintf(name, "res/p%d.png", i + 1);loadimage(&imgLion, name);imgLionArray.push_back(imgLion);}obstacleImgs.push_back(imgLionArray);// 初始化障碍物池for (int i = 0; i < OBSTACLE_COUNT; i++) {obstacles[i].exist = false;}// 加载下蹲素材loadimage(&imgHeroDown[0], "res/d1.png");loadimage(&imgHeroDown[1], "res/d2.png");heroDown = false;// 加载“柱子”障碍物IMAGE imgH;vector<IMAGE> imgHookArray;for (int i = 0; i < 4; i++) {sprintf_s(name, sizeof(name), "res/h%d.png", i + 1); //帧图片不够,补帧loadimage(&imgH, name, 63, 260, true);imgHookArray.push_back(imgH);obstacleImgs.push_back(imgHookArray);imgHookArray.pop_back();}heroBlood = 100;// 预加载音效preLoadSound("res/hit.mp3");lastObsIndex = -1;score = 0;}void checkScore() {for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist &&obstacles[i].passed == false &&obstacles[i].x + obstacleImgs[obstacles[i].type][0].getwidth() < heroX) {score++;obstacles[i].passed = true;printf("score: %d\n", score);}}
}void updateHero() {if (!heroDown) {putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);}else {int y = 345 - imgHeroDown[heroIndex].getheight();putimagePNG2(heroX, y, &imgHeroDown[heroIndex]);}}void HeroIndex()
{heroIndex = (heroIndex + 1) % 12;
}void checkWin() {if (score >= WIN_SCORE) {FlushBatchDraw();mciSendString("play res/win.mp3", 0, 0, 0);Sleep(2000);loadimage(0, "res/win.png");FlushBatchDraw();mciSendString("stop res/bg.mp3", 0, 0, 0);system("pause");heroBlood = 100;score = 0;mciSendString("play res/bg.mp3 repeat", 0, 0, 0);}
}int getDelay() {static unsigned long long lastTime = 0;unsigned long long currentTime = GetTickCount();if (lastTime == 0) {lastTime = currentTime;return 0;}else {int ret = currentTime - lastTime;lastTime = currentTime;return ret;}
}int main(void) {int timer = 0;init();// 显示初始画面loadimage(0, "res/over.png");system("pause");while (1) {keyEvent();timer += getDelay();//10if (timer > 20) {timer = 0;update = true;}if (update){update = false;BeginBatchDraw();updateBg();updateHero(); updateEnemy();updateBloodBar();checkWin();EndBatchDraw();moveBg();heroupdown();createObstacleData();checkHit();checkOver();checkScore();}}return 0;
}

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

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

相关文章

超详细-Vivado配置Sublime+Sublime实现Verilog语法实时检查

目录 一、前言 二、准备工作 三、Vivado配置Sublime 3.1 Vivado配置Sublime 3.2 环境变量添加 3.3 环境变量验证 3.4 Vivado设置 3.5 配置验证 3.6 解决Vivado配置失败问题 四、Sublime配置 4.1 Sublime安装Package Control 4.2 Sublime安装Verilog插件 4.3 安装语…

#pragma region用法

简介 #pragma region 是VS(Visio Studio)所特有的预处理语法&#xff08;其他IDE或者Cmake会报错&#xff09;&#xff0c;其可以用来收缩或者展开一段代码。 #pragma region MyRegion// ...Code content #pragma endregion 其中&#xff0c;MyRegion 即给这代码块所定义的名…

【计算机网络】简易TCP网络小程序

文章目录 1. 简易TCP网络程序1.1 服务端1.1.1 服务端创建套接字1.1.2 服务端绑定1.1.3 服务端监听1.1.4 服务端获取连接1.1.5 服务端处理请求 1.2 客户端1.2.1 客户端创建套接字1.2.2 客户端连接服务器1.2.3 客户端发起请求 1.3 服务器测试1.4 单执行流服务器的弊端 2. 多进程版…

【Java】 服务器cpu过高如何排查和解决?

文章目录 前言一、常见能够引起CPU100%异常的情况都有哪些&#xff1f;二、服务器CPU使用率飙升异常&#xff0c;黄金4步排查法三、排查 CPU 故障的常用命令四、什么场景会造成 CPU 低而负载确很高呢&#xff1f;五、监控发现线上机器内存占用率居高不下&#xff0c;如何分析进…

webpack require.context

require.context((directory: String),(includeSubdirs: Boolean) /* 可选的&#xff0c;默认值是 true */,(filter: RegExp) /* 可选的&#xff0c;默认值是 /^\.\/.*$/&#xff0c;所有文件 */,(mode: String) /* 可选的&#xff0c; sync | eager | weak | lazy | lazy-onc…

RPA界面元素定位与操控技术详解-达观数据

RPA 入门介绍 什么是 RPA&#xff1f;RPA 是机器人流程自动化 Robotic Process Automation 的简写。在《智能RPA实战》中&#xff0c;我们这样定义&#xff1a;通过特定的、可模拟人类在计算机界面上进行操作的技术&#xff0c;按照规则自动执行相应的流程任务&#xff0c;代替…

Linux QT通过NFS挂载到Linux开发板上

Linux QT通过NFS挂载到Linux开发板上 说明&#xff1a;这里使用的Linux开发板是正点原子的阿尔法开发板 创建NFS 环境 NFS简介 网络文件系统&#xff0c;英文 Network File System(NFS)&#xff0c;是由 SUN 公司研制的 UNIX 表示层协议 (presentation layer protocol)&…

【面试】MySQL 中InnoDB与MyISAM的区别是什么?

文章目录 前言一、数据库存储引擎二、如何知道自己的数据库用的什么引擎呢&#xff1f;三、存储引擎原理四、B 树和 B 树五、MyISAM六、InnoDB七、InnoDB与MyISAM的区别总结 前言 许多同学都把 MySQL 作为自己的数据库&#xff0c;但是可能用过最多的就是 SQL 语句&#xff0c…

【图像分类】基于LIME的CNN 图像分类研究(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码实现 &#x1f4a5;1 概述 基于LIME&#xff08;Local Interpretable Model-Agnostic Explanations&#xff09;的CNN图像分类研究是一种用于解释CNN模型的方法。LIME是一…

node中间件-express框架

文章目录 前置 Express安装1. 基本使用2. 中间件2.1 中间件应用 3. 中间件的注册方式3.1 普通中间件的注册3.2 path匹配中间件3.3 method与路径匹配3.4 案列中间件匹配与执行方法 4. 中间件request数据解析4.1 解析request body中间件4.2 urlencoded解析 5. 第三方中间件5.1 mo…

echarts图表如何自定义鼠标悬浮样式

样式调整 // formatter: {a}: {b}<br />{c}: {d}: {e} formatter: function (params) {// <i style"display:inline-block;border-radius:50%;width:4px;height:4px;background-color: #0ECB81;"></i>// ${console.log(params[0])}return <d…

android studio JNI开发

一、JNI的作用&#xff1a; 1.使Java与本地其他类型语言&#xff08;C、C&#xff09;交互&#xff1b; 2.在Java代码调用C、C等语言的代码 或者 C、C调用Java代码。 由于JAVA具有跨平台的特点&#xff0c;所以JAVA与本地代码的交互能力弱&#xff0c;采用JNI特性可以增强JA…

【收藏】用Vue.js来构建你的Web3应用,就像开发 Web2 一样熟悉

作为一名涉足去中心化网络的前端 JavaScript 开发人员&#xff0c;您可能遇到过许多 Web3 开发解决方案。但是&#xff0c;这些解决方案通常侧重于钱包集成和交易执行&#xff0c;这就造成了学习曲线&#xff0c;偏离了熟悉的 Web2 开发体验。 但不用担心&#xff01;有一种解…

导读页——记忆之路

记忆方法千千种&#xff0c;本栏意在梳理其中道道来&#xff0c;旦有小得&#xff0c;肥肠幸耶。从不同角度分析学习记忆。 文章目录 按方法分按有无逻辑分有逻辑用思维导图 无逻辑用记忆宫殿理论模仿借鉴 按方法分 学习方法–找书&#xff0c;背书&#xff0c;利器 按有无逻…

FastReport.Net FastReport.Core 2023.2.23 Crack

FastReport.Net & FastReport.Core 2023.2.23适用于 .NET 7、.NET Core、Blazor、ASP.NET、MVC 和 Windows 窗体的全功能报告库。它可用于 Microsoft Visual Studio 2022 和 JetBrains Rider。 利用数据呈现领域专家针对 .NET 7、.NET Core、Blazor、ASP.NET、MVC、Windo…

Jenkins从配置到实战(二) - Jenkins如何在多台机器上自动化构建

前言 jenkins除了支持在本机上进行项目构建&#xff0c;还可以将构建任务分发到其他远程服务器上去执行&#xff0c;可以实现在不同平台和架构的机器上来完成项目的自动化构建任务&#xff0c;也能减轻jenkins服务器的压力。本文章就主要介绍下此流程。 准备工作 准备两台机…

Redis—分布式系统

Redis—分布式系统 &#x1f50e;理解分布式&#x1f50e;分布式—应用服务与数据库服务分离引入更多的应用服务节点理解负载均衡 引入更多的数据库服务节点缓存分库分表 微服务 &#x1f50e;常见概念应用(Application) / 系统(System)模块(Module) / 组件(Component)分布式(D…

2023年最全OCR技术指南!预训练OCR大模型呼之欲出

OCR是一项科技革新&#xff0c;通过自动化大幅减少人工录入的过程&#xff0c;帮助用户从图像或扫描文档中提取文字&#xff0c;并将这些文字转换为计算机可读格式。这一功能在许多需要进一步处理数据的场景中&#xff0c;如身份验证、费用管理、自动报销、业务办理等都显得尤为…

【Linux】多线程概念理论

目录 1 什么是线程&#xff1f; 2 线程的优点 3 线程的缺点 4 线程异常 5 线程用途 6 Linux线程和进程对比 1 什么是线程&#xff1f; 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序列…

【目标跟踪】1、基础知识

文章目录 一、卡尔曼滤波二、匈牙利匹配 一、卡尔曼滤波 什么是卡尔曼滤波&#xff1f;——状态估计器 卡尔曼滤波用于在包含不确定信息的系统中做出预测&#xff0c;对系统下一步要做什么进行推测&#xff0c;且会结合推测值和观测值来得到修正后的最优值卡尔曼滤波就是利用…