【C++】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞
[导读]本系列博文内容链接如下:
【C++】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值
【C++】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动
【C++】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动【C++】做一个飞机空战小游戏(四)——给游戏添加背景音乐(多线程技巧应用)
【C++】做一个飞机空战小游戏(五)——getch()控制两个飞机图标移动(控制光标位置)
【C++】做一个飞机空战小游戏(六)——给两架飞机设置不同颜色(cout输出彩色字符、结构体使用技巧)
【C++】做一个飞机空战小游戏(七)——两组按键同时检测平滑移动(GetAsyncKeyState()函数应用)
【C++】做一个飞机空战小游戏(八)——生成敌方炮弹(rand()函数应用)
【C++】做一个飞机空战小游戏(九)——发射子弹的编程技巧
【C++】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞
今天这节介绍实现子弹击落炮弹、炮弹与飞机相撞的效果,增加了飞机的血量属性,炮弹撞击一次掉血三分之一,三次撞击则飞机被炮弹击落。还增加了飞机命数属性,飞机设置了3条命,飞机命数大于0的时候可以按复活键进行复活,如果命为0时,飞机不可复活。还增加了游戏暂停功能,按空格键游戏暂停,再按一次即可恢复游戏。
目录
一、炮弹与子弹或飞机相撞
(一)子弹击落炮弹
1、子弹、炮弹初始血量和伤害值
2、子弹与炮弹相撞后血量
3、击落函数
4、击落后血量变化代码
(二)炮弹与飞机相撞
1、飞机结构体
2、飞机初始化函数
(1)单个飞机初始化
(2)所有飞机初始化
3、飞机初始血量
4、飞机与炮弹相撞后血量
(1)炮弹血量
(2)飞机血量
5、飞机命数
6、相撞函数
7、相撞后血量命数变化代码
8、飞机复活
二、游戏暂停功能
(一)game中增加pause属性
(二)游戏暂停按键
(三)游戏暂停代码
三、完整代码
(一)主函数
(二)头文件control_plane.h
(三)库函数control_plane.cpp
四、运行效果
(一)子弹与炮弹相撞
(二)炮弹与飞机相撞、飞机复活
一、炮弹与子弹或飞机相撞
(一)子弹击落炮弹
1、子弹、炮弹初始血量和伤害值
子弹炮弹相撞前:
子弹、炮弹血量hp=1;
子弹、炮弹伤害值dam=1;
2、子弹与炮弹相撞后血量
子弹炮弹相撞后:
相撞后子弹血量=相撞前子弹血量-炮弹伤害值;
相撞后炮弹血量=相撞前炮弹血量-子弹伤害值;
因此,子弹炮弹相撞后,两者血量都为0,alive值都为false,会同归于尽,炮弹被击落。
3、击落函数
bool shoot(Bullet bullet,Bomb bomb)
{bool sbb,sx0,sx1,sy0,sy1;sx0=(bomb.location.x>=bullet.location.x-1);sx1=(bomb.location.x<=bullet.location.x+1); sy0=(bomb.location.y>=bullet.location.y);sy1=(bomb.location.y<=bullet.location.y+1); sbb=sx0 &&sx1&&sy0&&sy1;return sbb;
}
4、击落后血量变化代码
这部分代码在子弹位置更新线程中,具体如下:
for(int k=0;k<game.bombs_round;k++)//判断子弹是否击中炮弹
{ if(shoot(bullet[i][j],bomb[k])){bomb[k].hp-=bullet[i][j].dam;bullet[i][j].hp-=bomb[k].dam;}
}
(二)炮弹与飞机相撞
1、飞机结构体
//定义飞机结构体
typedef struct{Location location; //飞机坐标 int color; //飞机颜色 int icon; //飞机图标编号 direction_cmd keycmd; //飞机移动方向命令 bool fire; //飞机是否开火 int cnt_bullets; //按一次开火键加1,然后初始化bullet[cnt_bullets],子弹死亡一个减1int hp; //飞机血量 bool alive; //飞机存活标志 int No; //飞机序号 int life; //飞机命数
}Plane;
2、飞机初始化函数
(1)单个飞机初始化
//单个飞机初始化函数
Plane init_plane(Plane plane)
{plane.alive=true; plane.hp=3; plane.keycmd=none_cmd;plane.location=plocation[plane.No];plane.color=plane.No+1;plane.icon=plane.No+1; return plane;
}
初始化函数用在游戏开始和飞机复活时,函数中没有设置No和life两项,因为No值不同,而life值每次死亡时减1,复活后不能再恢复为原值。
(2)所有飞机初始化
//所有飞机初始化函数
void init_planes(void)
{for(int i=0;i<game.num_plane;i++)//刷新飞机图标{ plane[i]=init_plane(plane[i]);}
}
3、飞机初始血量
飞机初始血量hp=3,飞机没有设置伤害值,默认其伤害值为无穷大。
4、飞机与炮弹相撞后血量
(1)炮弹血量
炮弹与飞机相撞后,炮弹血量直接降为0,alive值为false。
(2)飞机血量
飞机与炮弹相撞后,相撞后飞机血量值=相撞前血量值-炮弹伤害值。飞机血量值小于等于0时,飞机死亡,alive值为false。
5、飞机命数
飞机命数life初始值为3。如果飞机死亡,其命数life值减1。
6、相撞函数
bool collide(Plane plane,Bomb bomb)
{bool cpb,cx0,cx1,cy0,cy1;cx0=bomb.location.x>=plane.location.x-1;cx1=bomb.location.x<=plane.location.x+plane_width;cy0=bomb.location.y>=plane.location.y;cy1=bomb.location.y<=plane.location.y+plane_height; cpb=cx0 && cx1 && cy0 && cy1;return cpb;
}
7、相撞后血量命数变化代码
飞机血量、命数的变化代码放置在炮弹位置更新线程中,具体内容如下:
for(int j=0;j<game.num_plane;j++)
{if(plane[j].alive){if(collide(plane[j],bomb[i])) {bomb[i].hp=0;plane[j].hp-=bomb[i].dam; }if(plane[j].hp<=0){plane[j].alive=false;plane[j].life=plane[j].life-1;plane[j].keycmd=none_cmd;plane[j].location.x=0;plane[j].location.y=b_b+8; } }}
8、飞机复活
按复活键可复活,当命数小于1时,不能再复活,永久死亡。plane[0]的复活代码如下:
if(plane[0].life>0)
{if (GetAsyncKeyState('O') & 0x8000) //飞机复活指令{plane[0]=init_plane(plane[0]);show_plane(plane[0]);}
}
二、游戏暂停功能
(一)game中增加pause属性
//定义游戏结构体
typedef struct{int stage; //游戏当前关 int bombs_round; //敌方每轮发射炮弹数量 int bombs_stage; //每关总计出现炮弹数量 bool clear; //游戏过关 bool complete; //游戏通关 bool gameover; //游戏结束int num_plane; //飞机数量 int cur_num_bomb; //当前已发射炮弹数量 int bomb_interval; //位置更新间隔 bool bomb_move; //炮弹是否移动bool bullet_move; //子弹是否移动bool pause; //游戏是否暂停
}Game;
(二)游戏暂停按键
游戏暂停键为空格键,游戏进行时,按下空格键game.pause=true,游戏暂停,再按一次game.pause=false,游戏恢复,代码在key()函数中,内容如下:
if (GetAsyncKeyState(VK_SPACE) & 0x8000)
{Sleep(50);game.pause=!game.pause;
}
代码中Sleep(50)为按键去抖动作用,防止按了一次被识别为多次。
(三)游戏暂停代码
游戏暂停时,主函数中除背景音乐之外所有的线程都暂停。在需要暂停的线程中加入如下代码:
while(game.pause)
{;
}
三、完整代码
(一)主函数
#include "control_plane.h"
#include "quenue.h"
using namespace std; Plane plane[eq_plane];
Game game;
Bomb bomb[eq_bombs_round];
Bullet bullet[eq_plane][eq_bullets_round];
Location plocation[]={{2*r_b/3,b_b},{r_b/3,b_b}};int main(int argc, char** argv) { init(); //初始化 bgmusic();//播放背景音乐getkey();bomb_location_update(); bullet_location_update(); while(1) //循环等待键盘指令 {while(game.pause){;}if(plane[0].keycmd!=none_cmd ||plane[1].keycmd!=none_cmd ||game.bomb_move ||game.bullet_move){game.bomb_move=false;game.bullet_move=false;system("cls");for(int i=0;i<game.num_plane;i++){if(plane[i].alive){show_plane(plane[i]);//刷新飞机图标}}for(int i=0;i<game.bombs_round;i++){if(bomb[i].alive){show_bomb(bomb[i]);}}for(int i=0;i<eq_plane;i++){for(int j=0;j<eq_bullets_round;j++){ if(bullet[i][j].alive){show_bullet(bullet[i][j]);}} } } }return 0;
}
(二)头文件control_plane.h
#ifndef CONTROL_PLANE_H
#define CONTROL_PLANE
#include <iostream>
#include <ctime>
#include <string>
#include<stdlib.h>
#include<windows.h>
#include <pthread.h>//导入线程头文件库
#include <mmsystem.h> //导入声音头文件库
#pragma comment(lib,"winmm.lib")//导入声音的链接库
#define _CRT_SECURE_NO_WARNINGS
using namespace std;#define t_b 0 //图形显示区域上侧边界
#define l_b 0 //图形显示区域左侧边界
#define r_b 100 //图形显示区域右侧边界
#define b_b 20 //图形显示区域下侧边界
#define plane_width 9
#define plane_height 6#define eq_plane 2 //飞机架数
#define eq_bombs_round 23 //eq=end quantity最终炮弹数量
#define eq_rt 10 //复活最大时间
#define eq_bullets_round 20 //eq=end quantity飞机一次发射最多子弹数量 //定义飞机造型
const string icon_plane1[]={" ■","■ ■ ■","■■■■■","■ ■ ■"," ■"," ■■■"};
const string icon_plane2[]={" ■","■ ■ ■","■■■■■"," ■"," ■■■","■■■■■"};//定义炮弹造型
const string icon_bomb="■";//定义子弹造型
const string icon_bullet="■";//定义坐标结构体
typedef struct{int x;int y;
} Location;//定义移动方向命令枚举类型
typedef enum {none_cmd,up_cmd,down_cmd,left_cmd,right_cmd} direction_cmd;//定义游戏结构体
typedef struct{int stage; //游戏当前关 int bombs_round; //敌方每轮发射炮弹数量 int bombs_stage; //每关总计出现炮弹数量 bool clear; //游戏过关 bool complete; //游戏通关 bool gameover; //游戏结束int num_plane; //飞机数量 int cur_num_bomb; //当前已发射炮弹数量 int bomb_interval; //位置更新间隔 bool bomb_move; //炮弹是否移动bool bullet_move; //子弹是否移动bool pause; //游戏是否暂停
}Game;//定义飞机结构体
typedef struct{Location location; //飞机坐标 int color; //飞机颜色 int icon; //飞机图标编号 direction_cmd keycmd; //飞机移动方向命令 bool fire; //飞机是否开火 int cnt_bullets; //按一次开火键加1,然后初始化bullet[cnt_bullets],子弹死亡一个减1int hp; //飞机血量 bool alive; //飞机存活标志 int No; //飞机序号 int life; //飞机命数
}Plane;//定义敌方炮弹结构体
typedef struct{Location location; //炮弹位置 bool alive; //炮弹是否存活 int color; //炮弹颜色string icon; //炮弹图标int rt; //rt=respawn time复活时间 int hp; //hp=hit point 生命值,此值<=0时,敌方炮弹死亡,敌方炮弹被飞机子弹击中hp会减少,坠地或与飞机相撞hp直接降为0 int dam; //dam=damage 伤害值int type; //炮弹类型
}Bomb;//定义子弹结构体
typedef struct{Location location; //子弹位置 bool alive; //子弹是否存活 int color; //子弹颜色string icon; //子弹图标 int hp; //hp=hit point 生命值,子弹击中炮弹或冲出屏幕上方hp直接降为0,子弹死亡 int dam; //dam=damage 伤害值int type; //子弹类型
}Bullet;extern Plane plane[eq_plane];
extern Game game;
extern Bomb bomb[eq_bombs_round];
extern Bullet bullet[eq_plane][eq_bullets_round];extern Location plocation[];
//extern Location plocation1={r_b/3,b_b};//声明刷新飞机位置函数
void show_plane(Plane plane);//获取键盘指令
void key(void);//更新所有飞机坐标
void plane_location_update(void);//初始化函数
void init(void);//播放背景音乐线程
void* thread_bgmusic(void* arg);
void play_bgmusic();
void bgmusic();//获取按键指令线程
void* thread_key(void* arg);
void getkey();//输出彩色字符函数
template<typename T> //T表示任何可以被cout输出的类型
void ColorCout(T t, const int ForeColor = 7, const int BackColor = 0);void init_bombs(void);
Bomb init_(Bomb bomb);
void* thread_bomb(void* arg);
void bomb_location_update();
void show_bomb(Bomb bomb);void bullet_location_update(); //子弹位置更新
void* thread_bullet(void* arg); //子弹线程函数
Bullet init_bullet(Bullet bullet); //单个子弹初始化
void init_bullets(void); //所有子弹初始化
Bullet fire(Plane plane,Bullet bullet); //飞机开火函数,确定子弹出现的起始位置
void show_bullet(Bullet bullet); //显示子弹图标 bool collide(Plane plane,Bomb bomb);
bool shoot(Bullet bullet,Bomb bomb);Plane init_plane(Plane plane);
void init_planes(void);#endif
(三)库函数control_plane.cpp
#include <iostream>
#include "conio.h"
#include <string>
#include "control_plane.h"
#include<windows.h>
using namespace std;//彩色输出函数
template<typename T> //T表示任何可以被cout输出的类型
void ColorCout(T t, const int ForeColor = 7, const int BackColor = 0)
{// 0 = 黑色 1 = 蓝色 2 = 绿色 3 = 浅绿色 4 = 红色 5 = 紫色 6 = 黄色 7 = 白色// 8 = 灰色 9 = 淡蓝色 10 = 淡绿色 11 = 淡浅绿色 12 = 淡红色 13 = 淡紫色 14 = 淡黄色 15 = 亮白色SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), ForeColor + BackColor * 0x10);cout << t;SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}//隐藏光标函数
HANDLE han = GetStdHandle(-11);
void hide(){CONSOLE_CURSOR_INFO cursor;cursor.bVisible = 0;cursor.dwSize = 1;SetConsoleCursorInfo(han,&cursor);
}//初始化函数
void init(void)
{plane[0].No=0;plane[1].No=1;plane[0].life=3; plane[1].life=3;srand(time(NULL));game.num_plane=2;game.bombs_round=3;game.bomb_move=false;game.bullet_move=false;game.bomb_interval=1000;game.stage=1;game.bombs_stage=100;game.pause=false; init_bombs();init_bullets();init_planes();system("cls");for(int i=0;i<game.num_plane;i++)//刷新飞机图标{ show_plane(plane[i]);}game.bombs_round=3;hide();//隐藏光标
}//********************************************************************************//以下三个函数为获得按键指令线程函数
//********************************************************************************void* thread_key(void* arg)
{while(1){Sleep(60); //获取指令延时一定时间,起滤波作用,延缓获取指令的响应速度 key(); //获取按键指令plane_location_update() ;//获取完指令马上更新飞机坐标 }
}
void getkey()
{pthread_t tid; pthread_create(&tid, NULL, thread_key, NULL);
}//获取键盘指令函数
void key(void)
{if (GetAsyncKeyState(VK_SPACE) & 0x8000){Sleep(50);game.pause=!game.pause; }if(!game.pause){if(plane[0].alive){direction_cmd c=none_cmd;if (GetAsyncKeyState(VK_UP) & 0x8000) c = up_cmd;if (GetAsyncKeyState(VK_DOWN) & 0x8000) c = down_cmd;if (GetAsyncKeyState(VK_LEFT) & 0x8000) c = left_cmd;if (GetAsyncKeyState(VK_RIGHT) & 0x8000) c = right_cmd;plane[0].keycmd=c; //刷新飞机方向指令 if (GetAsyncKeyState('P') & 0x8000) plane[0].fire = true; //飞机开火指令}else{if(plane[0].life>0){if (GetAsyncKeyState('O') & 0x8000) //飞机复活指令{plane[0]=init_plane(plane[0]);show_plane(plane[0]);}}}if(plane[1].alive){direction_cmd d=none_cmd;if (GetAsyncKeyState('W') & 0x8000) d = up_cmd;if (GetAsyncKeyState('S') & 0x8000) d = down_cmd;if (GetAsyncKeyState('A') & 0x8000) d = left_cmd;if (GetAsyncKeyState('D') & 0x8000) d = right_cmd;plane[1].keycmd=d;//刷新飞机图标if (GetAsyncKeyState('F') & 0x8000) plane[1].fire = true;}else{if(plane[1].life>0){if (GetAsyncKeyState('Q') & 0x8000){plane[1]=init_plane(plane[1]);show_plane(plane[1]);}} } }
}void gotoxy(int x, int y) {COORD pos = { x,y };HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出设备句柄SetConsoleCursorPosition(hOut, pos);//两个参数分别指定哪个窗口,具体位置
}//飞机图标刷新函数
void show_plane(Plane plane) //预先定义字符定位显示函数,x是列坐标,y是行坐标,原点(x=0,y=0)位于屏幕左上角
{int x,y;int i,j;int rows;x=plane.location.x;y=plane.location.y;switch(plane.icon){case 1://第一种造型 rows=sizeof(icon_plane1)/sizeof(icon_plane1[0]);for(i=0;i<rows;i++) {gotoxy(x,y+i); ColorCout(icon_plane1[i],plane.color);}break;case 2://第二种造型 rows=sizeof(icon_plane2)/sizeof(icon_plane2[0]);for(i=0;i<rows;i++) {gotoxy(x,y+i); ColorCout(icon_plane2[i],plane.color);}break; }
}//更新两个飞机的坐标
void plane_location_update(void)
{ for(int i=0;i<2;i++){if(plane[i].keycmd!=none_cmd) {int x,y;x=plane[i].location.x;y=plane[i].location.y;switch(plane[i].keycmd){case up_cmd:y--; //字符上移一行,行值y减1if(y<t_b) //限定y值最小值为0{y=t_b;}break;case down_cmd:y++; //字符下移一行,行值y加1if(y>b_b) //限定y高度 {y=b_b;}break;case left_cmd:x--; //字符左移一列,列值x减1if(x<l_b){x=l_b; //限定x最小值为0; }break;case right_cmd:x++; //字符右移一列,列值x加1if(x>r_b){x=r_b; //限定x宽度}break;}plane[i].location.x=x;plane[i].location.y=y;plane[i].keycmd=none_cmd; }}
}//单个炮弹初始化函数
Bomb init_bomb(Bomb bomb)
{bomb.location.x=rand()%r_b; bomb.location.y=b_b+6;bomb.icon=icon_bomb;bomb.color=6;bomb.dam=1;bomb.hp=1;bomb.alive=false;bomb.rt=rand()%(eq_rt+1)+1; return bomb;
}//所有炮弹初始化函数
void init_bombs(void)
{game.bomb_move=false;for(int i=0;i<game.bombs_round;i++){bomb[i]=init_bomb(bomb[i]); }
}//炮弹位置更新 线程
void* thread_bomb(void* arg)
{while(1){while(game.pause){;}Sleep(game.bomb_interval);game.bomb_move=true;for(int i=0;i<game.bombs_round;i++){ if(bomb[i].alive){bomb[i].location.y++;if(bomb[i].location.y>b_b+5){bomb[i].hp=0; }for(int j=0;j<game.num_plane;j++){if(plane[j].alive){if(collide(plane[j],bomb[i])) {bomb[i].hp=0;plane[j].hp-=bomb[i].dam; }if(plane[j].hp<=0){plane[j].alive=false;plane[j].life=plane[j].life-1;plane[j].keycmd=none_cmd;plane[j].location.x=0;plane[j].location.y=b_b+8; } }} if(bomb[i].hp<=0){bomb[i]=init_bomb(bomb[i]); } }else{bomb[i].rt--;if(bomb[i].rt<=0){bomb[i].alive=true;bomb[i].location.y=0;} }} }
}
//炮弹位置更新
void bomb_location_update()
{pthread_t tid; pthread_create(&tid, NULL, thread_bomb, NULL);
}炮弹图标刷新函数
void show_bomb(Bomb bomb) //预先定义字符定位显示函数,x是列坐标,y是行坐标,原点(x=0,y=0)位于屏幕左上角
{int x,y; x=bomb.location.x;y=bomb.location.y;hide();//隐藏光标gotoxy(x,y);ColorCout(bomb.icon,bomb.color);} //发射子弹
Bullet fire(Plane plane,Bullet bullet)
{game.bullet_move=true;bullet.location.x=plane.location.x+plane_width/2; bullet.location.y=plane.location.y-1;bullet.alive=true; return bullet;
}//单个子弹初始化函数
Bullet init_bullet(Bullet bullet)
{bullet.icon=icon_bullet;bullet.location.x=0;bullet.location.y=b_b+7;bullet.alive=false;bullet.color=4;bullet.dam=1;bullet.hp=1; return bullet;
}//所有子弹初始化函数
void init_bullets(void)
{game.bullet_move=false; for(int i=0;i<eq_plane;i++){for(int j=0;j<eq_bullets_round;j++){bullet[i][j]=init_bullet(bullet[i][j]); } }
}//单个飞机初始化函数
Plane init_plane(Plane plane)
{plane.alive=true; plane.hp=3; plane.keycmd=none_cmd;plane.location=plocation[plane.No];plane.color=plane.No+1;plane.icon=plane.No+1; return plane;
}//所有飞机初始化函数
void init_planes(void)
{for(int i=0;i<game.num_plane;i++)//刷新飞机图标{ plane[i]=init_plane(plane[i]);}
}//子弹位置更新 线程
void* thread_bullet(void* arg)
{while(1){while(game.pause){;}Sleep(game.bomb_interval);for(int i=0;i<eq_plane;i++){if(plane[i].fire) //如果飞机开火,要搜寻一个子弹处于死亡状态的位置激活子弹 { game.bullet_move=true; for(int j=0;j<eq_bullets_round;j++){if(!bullet[i][j].alive){bullet[i][j]=fire(plane[i],bullet[i][j]);break;} }}plane[i].fire=false; }for(int i=0;i<eq_plane;i++){for(int j=0;j<eq_bullets_round;j++){ if(bullet[i][j].alive){bullet[i][j].location.y--;if(bullet[i][j].location.y<0){bullet[i][j].hp=0; }for(int k=0;k<game.bombs_round;k++)//判断子弹是否击中炮弹 { if(shoot(bullet[i][j],bomb[k])){bomb[k].hp-=bullet[i][j].dam;bullet[i][j].hp-=bomb[k].dam;}}if(bullet[i][j].hp<=0){//bullet[i][j].alive=false;bullet[i][j]=init_bullet(bullet[i][j]); } }} } }
}
//子弹位置更新
void bullet_location_update()
{pthread_t tid; pthread_create(&tid, NULL, thread_bullet, NULL);
}子弹图标刷新函数
void show_bullet(Bullet bullet) //预先定义字符定位显示函数,x是列坐标,y是行坐标,原点(x=0,y=0)位于屏幕左上角
{int x,y; x=bullet.location.x;y=bullet.location.y;hide();//隐藏光标gotoxy(x,y);ColorCout(bullet.icon,bullet.color);
} //********************************************************************************//以下函数为子弹被击落或撞落功能
//********************************************************************************bool collide(Plane plane,Bomb bomb)
{bool cpb,cx0,cx1,cy0,cy1;cx0=bomb.location.x>=plane.location.x-1;cx1=bomb.location.x<=plane.location.x+plane_width;cy0=bomb.location.y>=plane.location.y;cy1=bomb.location.y<=plane.location.y+plane_height; cpb=cx0 && cx1 && cy0 && cy1;return cpb;
}bool shoot(Bullet bullet,Bomb bomb)
{bool sbb,sx0,sx1,sy0,sy1;sx0=(bomb.location.x>=bullet.location.x-1);sx1=(bomb.location.x<=bullet.location.x+1); sy0=(bomb.location.y>=bullet.location.y);sy1=(bomb.location.y<=bullet.location.y+1); sbb=sx0 &&sx1&&sy0&&sy1;return sbb;
}//********************************************************************************//以下三个函数为播放背景音乐功能
//********************************************************************************//播放一遍背景音乐 void play_bgmusic() { mciSendString(TEXT("open hero.mp3 alias s1"),NULL,0,NULL);mciSendString(TEXT("play s1"),NULL,0,NULL);Sleep(153*1000);//153*1000意思是153秒,是整首音乐的时长 mciSendString(TEXT("close S1"),NULL,0,NULL); }//循环播放音乐线程函数
void* thread_bgmusic(void* arg) //
{ while(1){ play_bgmusic();}
} //创建音乐播放线程,开始循环播放音乐
void bgmusic()
{pthread_t tid; pthread_create(&tid, NULL, thread_bgmusic, NULL);
}
四、运行效果
(一)子弹与炮弹相撞
(二)炮弹与飞机相撞、飞机复活
(未完待续)
相关文章:
【C++】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞
[导读]本系列博文内容链接如下: 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…...
去除UI切图边缘上多余的线条
最近接到UI切图,放进项目,显示边缘有多余线条,影响UI美观。开始以为切图没切好,实则不是。如图: ->解决: 将该图片资源WrapMode改为Clamp...
Spring高手之路13——BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor解析
文章目录 1. BeanFactoryPostProcessor 概览1.1 解读 BeanFactoryPostProcessor1.2. 如何使用 BeanFactoryPostProcessor 2. BeanDefinitionRegistryPostProcessor 深入探究2.1 解读 BeanDefinitionRegistryPostProcessor2.2 BeanDefinitionRegistryPostProcessor 的执行时机2.…...
【LeetCode动态规划】详解买卖票I~IV,经典dp题型买
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。…...
【深入探究人工智能】:常见机器学习算法总结
文章目录 1、前言1.1 机器学习算法的两步骤1.2 机器学习算法分类 2、逻辑回归算法2.1 逻辑函数2.2 逻辑回归可以用于多类分类2.3 逻辑回归中的系数 3、线性回归算法3.1 线性回归的假设3.2 确定线性回归模型的拟合优度3.3线性回归中的异常值处理 4、支持向量机(SVM&a…...
设计模式之解释器模式详解及实例
1、解释器设计模式概述: 解释器模式(Interpreter Pattern)是一种设计模式,它主要用于描述如何构建一个解释器以解释特定的语言或表达式。该模式定义了一个文法表示和解释器的类结构,用于解释符合该文法规则的语句。解…...
Nodejs沙箱逃逸--总结
一、沙箱逃逸概念 JavaScript和Nodejs之间有什么区别:JavaScript用在浏览器前端,后来将Chrome中的v8引擎单独拿出来为JavaScript单独开发了一个运行环境,因此JavaScript也可以作为一门后端语言,写在后端(服务端&#…...
No115.精选前端面试题,享受每天的挑战和学习
文章目录 变量提升和函数提升的顺序Event Loop封装 FetchAPI,要求超时报错的同时,取消执行的 promise(即不继续执行)强缓存和协商缓存的区别token可以放在cookie里吗? 变量提升和函数提升的顺序 在JavaScript中&#…...
Elasticsearch:语义搜索 - Semantic Search in python
当 OpenAI 于 2022 年 11 月发布 ChatGPT 时,引发了人们对人工智能和机器学习的新一波兴趣。 尽管必要的技术创新已经出现了近十年,而且基本原理的历史甚至更早,但这种巨大的转变引发了各种发展的“寒武纪大爆炸”,特别是在大型语…...
Flink学习笔记(一)
流处理 批处理应用于有界数据流的处理,流处理则应用于无界数据流的处理。 有界数据流:输入数据有明确的开始和结束。 无界数据流:输入数据没有明确的开始和结束,或者说数据是无限的,数据通常会随着时间变化而更新。 在…...
[Raspberry Pi]如何用VNC遠端控制樹莓派(Ubuntu desktop 23.04)?
之前曾利用VMware探索CentOS,熟悉Linux操作系統的指令和配置運作方式,後來在樹莓派價格飛漲的時期,遇到貴人贈送Raspberry Pi 4 model B / 8GB,這下工具到位了,索性跳過樹莓派官方系統(Raspberry Pi OS),直…...
17.HPA和rancher
文章目录 HPA部署 metrics-server部署HPA Rancher部署Rancherrancher添加集群仪表盘创建 namespace仪表盘创建 Deployments仪表盘创建 service 总结 HPA HPA(Horizontal Pod Autoscaling)Pod 水平自动伸缩,Kubernetes 有一个 HPA 的资源&…...
VS2022远程Linux使用cmake开发c++工程配置方法
文章目录 远程连接CMakePresets.json的配置Task.vs.json配置launch.vs.json配置最近使用别人在VS2015上使用visualgdb搭建的linux开发环境,各种不顺手,一会代码不能调转了,一会行号没了,调试的时候断不到正确的位置,取消的断点仍然会进。因此重新摸索了一套使用vs的远程开…...
《强化学习:原理与Python实战》——可曾听闻RLHF
前言: RLHF(Reinforcement Learning with Human Feedback,人类反馈强化学习)是一种基于强化学习的算法,通过结合人类专家的知识和经验来优化智能体的学习效果。它不仅考虑智能体的行为奖励,还融合了人类专家…...
STM32——RTC实时时钟
文章目录 Unix时间戳UTC/GMT 时间戳转换BKP简介BKP基本结构读写BKP备份寄存器电路设计关键代码 RTC简介RTC框图RTC基本结构硬件电路RTC操作注意事项读写实时时钟电路设计关键代码 Unix时间戳 Unix 时间戳(Unix Timestamp)定义为从UTC/GMT的1970年1月1日…...
webSocket 开发
1 认识webSocket WebSocket_ohana!的博客-CSDN博客 一,什么是websocket WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议)它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽…...
c#设计模式-结构型模式 之 代理模式
前言 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接 引用目标对象,代理对象作为访问对象和目标对象之间的中介。在学习代理模式的时候,可以去了解一下Aop切面编程AOP切面编程_aop编程…...
openpnp - 自动换刀的设置
文章目录 openpnp - 自动换刀的设置概述笔记采用的openpnp版本自动换刀库的类型选择自动换刀设置前的注意事项先卸掉吸嘴座上所有的吸嘴删掉所有的吸嘴设置自动换刀的视觉识别设置吸嘴座为自动换刀 - 以N1为例备注补充 - 吸嘴轴差个0.3mm, 就有可能怼坏吸嘴END openpnp - 自动换…...
《HeadFirst设计模式(第二版)》第十章代码——状态模式
如下图所示,这是一个糖果机的状态机图,要求使用代码实现: 初始版本: package Chapter10_StatePattern.Origin;/*** Author 竹心* Date 2023/8/19**/public class GumballMachine {final static int SOLD_OUT 0;final static int…...
day-25 代码随想录算法训练营(19)回溯part02
216.组合总和||| 思路:和上题一样,差别在于多了总和,但是数字局限在1-9 17.电话号码的字母组合 思路:先纵向遍历第i位电话号码对于的字符串,再横向递归遍历下一位电话号码 93.复原IP地址 画图分析: 思…...
PG逻辑备份与恢复
文章目录 创建测试数据pg_dump 备份pg_restore 恢复pg_restore 恢复并行备份的文件PG 只导出指定函数 创建测试数据 drop database if exists test; create database test ; \c test create table t1(id int primary key); create table t2(id serial primary key, name varch…...
图数据库_Neo4j和SpringBoot整合使用_实战创建明星关系图谱---Neo4j图数据库工作笔记0010
然后我们再来看一下这个明星关系图谱 可以看到这里 这个是原来的startRelation 我们可以写CQL去查询对应的关系 可以看到,首先查询出来以后,然后就可以去创建 我们可以把写的创建明星关系的CQL,拿到 springboot中去执行 可以看到,这里我们先写一个StarRelationRepository,然…...
Linux网络编程:Socket套接字编程(Server服务器 Client客户端)
文章目录: 一:定义和流程分析 1.定义 2.流程分析 3.网络字节序 二:相关函数 IP地址转换函数inet_pton inet_ntop(本地字节序 网络字节序) socket函数(创建一个套接字) bind函数(给socket绑定一个服务器地址结…...
Mac OS下应用Python+Selenium实现web自动化测试
在Mac环境下应用PythonSelenium实现web自动化测试 在这个过程中要注意两点: 1.在终端联网执行命令“sudo pip install –U selenium”如果失败了的话,可以尝试用命令“sudo easy_install selenium”来安装selenium; 2.安装好PyCharm后新建project&…...
每天一道leetcode:934. 最短的桥(图论中等广度优先遍历)
今日份题目: 给你一个大小为 n x n 的二元矩阵 grid ,其中 1 表示陆地,0 表示水域。 岛 是由四面相连的 1 形成的一个最大组,即不会与非组内的任何其他 1 相连。grid 中 恰好存在两座岛 。 你可以将任意数量的 0 变为 1 &#…...
【学习日记】【FreeRTOS】FreeRTOS 移植到 STM32F103C8
前言 本文基于野火 FreeRTOS 教程,内容是关于 FreeRTOS 官方代码的移植的注意事项,并将野火例程中 STM32F103RC 代码移植到 STM32F103C8。 一、FreeRTOS V9.0.0 源码的获取 两个下载链接: 官 网 代码托管 二、源码文件夹内容简介 Source…...
Qt 屏幕偶发性失灵
项目场景: 基于NXP i.mx7的Qt应用层项目开发,通过goodix使用触摸屏,走i2c协议。 问题描述 触摸屏使用过程中意外卡死,现场分为多种: i2c总线传输错误,直观表现为触摸屏无效,任何与触摸屏挂接在同一总线上的i2c设备,均受到干扰,并且在传输过程中内核报错以下代码: G…...
如何在pycharm中指定GPU
如何在pycharm中指定GPU 作者:安静到无声 个人主页 目录 如何在pycharm中指定GPU打开编辑配置点击环境变量添加GPU配置信息推荐专栏在Pycharm运行程序的时候,有时候需要指定GPU,我们可以采用以下方式进行设置: 打开编辑配置 点击环境变量 添加GPU配置信息 添加名称:CU…...
C#判断字符串中有没有字母,正则表达式、IsLetter
要判断字符串中是否包含字母,可以使用正则表达式或者循环遍历字符串的方式。 方法一:使用正则表达式 using System.Text.RegularExpressions;string input "Hello123"; bool containsLetter Regex.IsMatch(input, "[a-zA-Z]");上…...
Jtti:Ubuntu怎么限制指定端口和IP访问
在 Ubuntu 系统中,可以使用防火墙规则来限制特定的端口和IP访问。常用的防火墙管理工具是 iptables,以下是使用 iptables 来限制指定端口和IP访问的步骤: 安装 iptables: 如果系统中没有安装 iptables,可以使用以下命…...
茂县建设局网站/自制网页
自从软件业诞生后,虚拟世界得以与真实世界并行,二者互相依存,生生不息。软件有一些特殊的属性,与真实世界中的物质的属性不同,有些甚至完全相反,比如: 一. 软件无新旧 在真实世界中,…...
网站建设公司要求什么/chrome浏览器官网入口
一、 打开终端(Terminal)下载源码: git clone https://github.com/Sunnyyoung/WeChatTweak- - macOS.git进入目录:cd WeChatTweak-macOS编译安装:sudo make install卸载动态库 sudo make uninstall打开微信客户端 二…...
css网站做光晕效果/seo搜索引擎优化实战
来源:乌枭 链接:https://blog.csdn.net/qq_34039315/article/details/785493111、在java中守护线程和本地线程区别?java中的线程分为两种:守护线程(Daemon)和用户线程(User)。任何…...
怎样做旅游网站/美国今天刚刚发生的新闻
IO的分类 IO IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。 IO流的简单分类 按照流的流向分,可以分为输入流和输出流;按照操作单元划分,可以划分为字节流和字符流;按照流的角色划分为节点…...
一个网站如何做推广/seo优化入门教程
从MySQL5.6开始,mysqlbinlog支持将远程服务器上的binlog实时复制到本地服务器上。mysqlbinlog的实时二进制复制功能并非简单的将远程服务器的日志复制过来,它是通过MySQL 5.6公布的Replication API实时获取二进制事件。本质上,就相当于MySQL的…...
网站绑定微信号/百度竞价怎么操作
junit 报错 java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayNametestSelectByExample], 坑了我三个点的问题 不是没写 Test,不是 public,参数,返回值,修饰符的错误,也不是 spring 包与 junit 的…...