【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],子弹死亡一个减1
	int 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],子弹死亡一个减1
	int 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减1
					if(y<t_b)			//限定y值最小值为0
					{
						y=t_b;
					}
					break;
				case down_cmd:
					y++;				//字符下移一行,行值y加1
					if(y>b_b)			//限定y高度 
					{
						y=b_b;
					}
					break;
				case left_cmd:
					x--;				//字符左移一列,列值x减1
					if(x<l_b)
					{
						x=l_b;			//限定x最小值为0; 
					}
					break;
				case right_cmd:
					x++;				//字符右移一列,列值x加1
					if(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);
}

四、运行效果

(一)子弹与炮弹相撞

(二)炮弹与飞机相撞、飞机复活

 (未完待续)

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

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

相关文章

Linux笔试题(4)

67、在局域网络内的某台主机用ping命令测试网络连接时发现网络内部的主机都可以连同,而不能与公网连通,问题可能是__C_ A.主机ip设置有误 B.没有设置连接局域网的网关 C.局域网的网关或主机的网关设置有误 D.局域网DNS服务器设置有误 解析&#xff1a;在局域网络内的某台主…

视频怎么转gif高清动图?分享一款视频转gif工具

许多小伙伴都不知道如何将拍摄的短视频转gif图片&#xff0c;本文将分享一款专业的视频转gif工具&#xff0c;打来浏览器即可将视频在线转gif&#xff08;https://www.gif.cn&#xff09;&#xff0c;操作简单&#xff0c;使用方便&#xff0c;下面是详细的步骤。 打开网站&am…

linux系统服务学习(六)FTP服务学习

文章目录 FTP、NFS、SAMBA系统服务一、FTP服务概述1、FTP服务介绍2、FTP服务的客户端工具3、FTP的两种运行模式&#xff08;了解&#xff09;☆ 主动模式☆ 被动模式 4、搭建FTP服务&#xff08;重要&#xff09;5、FTP的配置文件详解&#xff08;重要&#xff09; 二、FTP任务…

实验一 VMware 17 虚拟机下安装Ubuntu16.04

系列文章目录 文章目录 系列文章目录前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 古人云&#xff1a;“工欲善其事&#xff0c;必先利其器。” 我们在学习分布式数据库原理知识同时少不了实操&#xff0c;在做实验之前&#xff0c;把相关实验…

AI 绘画Stable Diffusion 研究(十二)SD数字人制作工具SadTlaker插件安装教程

免责声明: 本案例所用安装包免费提供&#xff0c;无任何盈利目的。 大家好&#xff0c;我是风雨无阻。 想必大家经常看到&#xff0c;无论是在产品营销还是品牌推广时&#xff0c;很多人经常以数字人的方式来为自己创造财富。而市面上的数字人收费都比较昂贵&#xff0c;少则几…

解决多模块内核心模块有接口打包成jar后被依赖并调用遇到的问题(springcloud集成ruoyi.quartz)

项目准备开发个新功能&#xff0c;刚好很喜欢ruoyi写的任务调度&#xff0c;因此想到了集成ruoyi.quartz模块 &#xff0c;遇到了很多问题: 首先因为ruoyi.quartz模块依赖了ruoyi.common模块&#xff0c;因此第一步我需要把common模块一部分依赖项复制到了quartz模块内&#xf…

Python 的下一代 HTTP 客户端

迷途小书童 读完需要 9分钟 速读仅需 3 分钟 1 环境 windows 10 64bitpython 3.8httpx 0.23.0 2 简介 之前我们介绍过使用 requests ( https://xugaoxiang.com/2020/11/28/python-module-requests/ ) 来进行 http 操作&#xff0c;本篇介绍另一个功能非常类似的第三方库 httpx&…

pointnet C++推理部署--tensorrt框架

classification 如上图所示&#xff0c;由于直接export出的onnx文件有两个输出节点&#xff0c;不方便处理&#xff0c;所以编写脚本删除不需要的输出节点193&#xff1a; import onnxonnx_model onnx.load("cls.onnx") graph onnx_model.graphinputs graph.inpu…

时序预测 | MATLAB实现WOA-CNN-LSTM鲸鱼算法优化卷积长短期记忆神经网络时间序列预测

时序预测 | MATLAB实现WOA-CNN-LSTM鲸鱼算法优化卷积长短期记忆神经网络时间序列预测 目录 时序预测 | MATLAB实现WOA-CNN-LSTM鲸鱼算法优化卷积长短期记忆神经网络时间序列预测预测效果基本介绍模型描述程序设计学习总结参考资料 预测效果 基本介绍 时序预测 | MATLAB实现WOA-…

VBA技术资料MF45:VBA_在Excel中自定义行高

【分享成果&#xff0c;随喜正能量】可以不光芒万丈&#xff0c;但不要停止发光。有的人陷入困境&#xff0c;不是被人所困&#xff0c;而是自己束缚自己&#xff0c;这时"解铃还须系铃人"&#xff0c;如果自己无法放下&#xff0c;如何能脱困&#xff1f; 。 我给V…

03_缓存双写一致性

03——缓存双写一致性 一、缓存双写一致性 如果redis中有数据&#xff0c;需要和数据库中的值相同如果redis中无数据&#xff0c;数据库中的值要是最新值&#xff0c;且准备回写redis 缓存按照操作来分&#xff0c;可以分为两种&#xff1a; 只读缓存 读写缓存 同步直写操作…

解决:(error) ERR unknown command shutdow,with args beginning with

目录 一、遇到问题 二、出现问题的原因 三、解决办法 一、遇到问题 要解决连接redis闪退的问题&#xff0c;按照许多的方式去进行都没有成功&#xff0c;在尝试使用了以下的命名去尝试时候&#xff0c;发现了这个问题。 二、出现问题的原因 这是一个粗心大意导致的错误&am…

Azure静态网站托管

什么是静态网站托管 Azure Blob的静态网站托管是一项功能&#xff0c;它允许开发人员在Azure Blob存储中托管和发布静态网站。通过这个功能&#xff0c;您可以轻松地将静态网页、图像、视频和其他网站资源存储在Azure Blob中&#xff0c;并直接通过提供的URL访问这些资源。 官…

什么是变量提升(hoisting)?它在JavaScript中是如何工作的?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 变量提升&#xff08;Hoisting&#xff09;⭐ 变量提升的示例&#xff1a;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&…

Android 场景Scene的使用

Scene 翻译过来是场景&#xff0c;开发者提供起始布局和结束布局&#xff0c;就可以实现布局之间的过渡动画。 具体可参考 使用过渡为布局变化添加动画效果 大白话&#xff0c;在 Activity 的各个页面之间切换&#xff0c;会带有过渡动画。 打个比方&#xff0c;使用起来类似…

回归预测 | MATLAB实现IPSO-SVM改进粒子群优化算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现IPSO-SVM改进粒子群优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现IPSO-SVM改进粒子群优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xf…

保险龙头科技进化论:太保的六年

如果从2013年中国首家互联网保险公司——众安在线的成立算起&#xff0c;保险科技在我国的发展已走进第十个年头。十年以来&#xff0c;在政策指引、技术发展和金融机构数字化转型的大背景下&#xff0c;科技赋能保险业高质量发展转型已成为行业共识。 大数据、云计算、人工智…

unity 之Transform组件(汇总)

文章目录 理论指导结合例子 理论指导 当在Unity中处理3D场景中的游戏对象时&#xff0c;Transform 组件是至关重要的组件之一。它管理了游戏对象的位置、旋转和缩放&#xff0c;并提供了许多方法来操纵和操作这些属性。以下是关于Transform 组件的详细介绍&#xff1a; 位置&a…

初步认识OSI/TCP/IP一(第三十八课)

1 初始OSI模型 OSI参考模型(Open Systems Interconnection Reference Model)是一个由国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的网络通信协议规范,它将网络通信分为七个不同的层次,每个层次负责不同的功能和任务。 2 网络功能 数据通信、资源共…

网络安全---webshell实践

一、首先环境配置 1.上传文件并解压 2.进入目录下 为了方便解释&#xff0c;我们只用两个节点&#xff0c;启动之后&#xff0c;大家可以看到有 3 个容器&#xff08;可想像成有 3 台服务器就成&#xff09;。 二、使用蚁剑去连接 因为两台节点都在相同的位置存在 ant.jsp&…