基于C语言和EasyX图形库的简单飞行射击小游戏

基于C语言和EasyX图形库的简单飞行射击小游戏

基本游戏逻辑介绍

  本次编写的游戏是一个空战小游戏,实现了一些简单的游戏功能。如主菜单和子菜单游戏界面均通过鼠标点击进行操作,通过按键来控制游戏角色的移动以及技能的释放。
  下面简单的介绍一下游戏的大概流程和思路。 首先,对于游戏中的个体,存在着很多的信息,所以我们定义不同的结构体来存储这些个体的各种信息,如是否存活、子弹等级、敌机的种类、PH值等。关于easyx图形库就不做过多的介绍,大家可以自行去了解
  游戏先进入主菜单,通过循环来实现获取鼠标信息,在通过判定鼠标是否点击以及点击的位置,达到选择不同功能的效果。选择开始游戏后跳出主菜单循环,进入游戏循环,通过定义不同的功能函数来实现角色的移动、图片的刷新、以及一部分简单的动态效果。通过GetKeyState()函数来判断用户是否按下移动键。进行移动,改变图片坐标位置。再产生敌机和敌机子弹,敌机和子弹的移动(通过改变坐标实现移动),判定是否被子弹击中或者与敌机碰撞。最后调用画地图的函数,将所有的图片画出。游戏死亡之后、暂停、退出等的功能与主菜单同理,通过鼠标控制(使用goto语句实现返回主菜单、重新开始游戏)。游戏还有能保存游戏分数的最好历史记录,涉及一些简单的文件操作。

在编写过程中遇见的一些坑

  • 在图片的打印中会有闪烁的问题,这里使用双缓冲解决BeginBatchDraw();FlushBatchDraw();
  • 在实现暂停功能时,会有暂停的图片呈现,建议将图片设置成窗口大小,当你暂停时的图片比地图更小时,会有鼠标操作不灵敏的问题(若能解决建议还是比地图小一些),即需要点击多次才可能触发你的判断。
  • 敌机和子弹需要使用透明贴图,所以需要掩码图和原图来实现透明贴图。如
putimage(minePlan.x, minePlan.y, &minebit[0], NOTSRCERASE);
putimage(minePlan.x, minePlan.y, &mine[0], SRCINVERT);

参考链接:如何制作掩码图

  • 多种音效同时播放需要使用简单的多线程,否则会导致游戏卡顿。如背景音效和爆炸音效同时播放。请读者自行查阅资料。
  • 动态爆炸的实现,当使用多线程实现时,有爆炸闪烁的效果(这个问题还未解决),可以在打印图片的函数中实现。原理:每次图刷新都会打印爆炸的图片(地图刷新的速度很快),通过控制打印不同的图片实现爆炸效果(需要控制图片更新的时间),类似于通过快速翻动画在纸上的图片达到动态的效果,具体操作,参考代码。

头文件代码

头文件定义代码,函数的声明较少是因为在主文件中用到的函数较少,大多数函数的调用在AirGame.cpp中

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>//文件操作的头文件sprintf()函数
#include<stdlib.h>
#include<conio.h>#include<windows.h> //GetKeyState()函数需要
#include<mmsystem.h>//playSound()函数需要.包含多媒体设备接口库
#include<math.h>//rand()随机函数需要#pragma 
comment(lib,"Winmm.lib")//导入Winmm.lib库,让歌曲可以播放
#include<graphics.h>//easyx图形库的头文件
#include<process.h>#define NUM 20 //敌机数组数量
#define WIDTH 600	//地图宽600  
#define HEIGHT 700	//高700		
#define N  15//子弹数量
#define BOSSBUL 100//boss子弹量
#undef UNICODE //解决loadimage()的加载出问题的问题  
//定义我方飞机和敌方飞机坐标血量,子弹等...
typedef struct role//我方飞机
{	
int x;	//确定在图中的坐标	
int y;	
int type;	//我方飞机子弹等级	
int kind;	//我方飞机种类	
int live;	//飞机是否存活	
int score; //存储分数
}Role;
typedef struct enemy  //敌机
{	
int x;	//确定在图中的坐标	
int y;	
int type;	//敌机飞机种类.	
int live;	//飞机是否存活	
int HP;		//血量
char shot;	//表示飞机是否发射过子弹
}Enemy; 
typedef struct _bullte //子弹
{	int x;	//确定在图中的坐标	
int y;	
int live;	//子弹是否存活	
char shot;	//导弹是否发射
}Bullte; 
typedef struct ico	//图标
{	
int x;	//确定在图中的坐标	
int y;	
int live;	//飞机、子弹是否存活	
}Ico;
char PlayKeyboard(char c);
void texiao();
void image(IMAGE *map1, Role *minePlan);//图片加载//飞机移动
int keyDown(IMAGE* map1, int speed);//画出飞机移动后的地图
void drowGame();
void planMove(char c,IMAGE *mine);
 char GameOver();//游戏结束后 
 void DataConserve();//保存数据并退出 
 void  OutScore(int number);//输出数字图片 
 int timeout();//暂停函数 
 int  Datadir();//记录查看

Main.cpp代码

#include"airHead.h"
//定义图片变量
IMAGE map1, mine[2],map[7],tubiao[10], shuzi[3], shuziyama[3];
Role minePlan;//定义我方飞机
DWORD t1, t2,t3,t4,t5,t6,t7,t8;//什么变量
IMAGE enemy2[5], enemy2yanma[5];
int img_x, img_y;
//IMAGE tu[2];
int Num[7], count = 0;
int MainMenu()
{
	MOUSEMSG m, m2, m3, m4;//定义鼠标变量
	while (1)//主菜单操作
	{
		putimage(0, 0, &map[0]);
		FlushBatchDraw();
		m = GetMouseMsg();
		if (m.uMsg == WM_LBUTTONDOWN)//当鼠标左键按下
		{
			if (m.x > 230 && m.x < 371 && m.y>46 && m.y < 83)//选择角色
			{
				putimage(0, 0, &map[5]);//角色选择界面
				FlushBatchDraw();
				while (1)
				{
					m3 = GetMouseMsg();
					if (m3.uMsg == WM_LBUTTONDOWN)//当鼠标左键按下
					{
						if (m3.x < 147 && m3.x>57 && m3.y > 210 && m3.y < 291)//1号机
						{
							minePlan.kind = 1;
							break;
						}
						if (m3.x < 537 && m3.x>449 && m3.y > 210 && m3.y < 291)//2号机
						{
							minePlan.kind = 2;
							break;
						}
					}
				}
			}
			if (m.x > 230 && m.x < 371 && m.y>154 && m.y < 193)//开始游戏
			{
				break;
			}
			if (m.x > 230 && m.x < 371 && m.y>270 && m.y < 306)//退出游戏
			{
				DataConserve();
				return 0;
			}
			if (m.x > 230 && m.x < 371 && m.y>381 && m.y < 421)//游戏记录
			{
				putimage(0, 0, &map[6]);//显示历史最高纪录
				putimage(0, 0, &tubiao[0], NOTSRCERASE);
				putimage(0, 0, &tubiao[1], SRCINVERT);
				int score = Datadir();
				//输出位置
				img_x = 196;
				img_y = 275;
				count = 0;//数组下标归零
				if (score == -1)
					OutScore(0);
				else
					OutScore(score);
				FlushBatchDraw();
				while (1)
				{
					m4 = GetMouseMsg();
					if (m4.uMsg == WM_LBUTTONDOWN)//当鼠标左键按下
					{
						if (m4.x < 50 && m4.x>0 && m4.y > 0 && m4.y < 50)
						{
							break;
						}
					}
				}
			}
			if (m.x > 230 && m.x < 371 && m.y>484 && m.y < 3524)//游戏帮助
			{
				putimage(0, 0, &map[1]);//显示游戏操作说明
				putimage(0, 0, &tubiao[0], NOTSRCERASE);
				putimage(0, 0, &tubiao[1], SRCINVERT);
				FlushBatchDraw();
				while (1)
				{
					m2 = GetMouseMsg();
					if (m2.uMsg == WM_LBUTTONDOWN)//当鼠标左键按下
					{
						if (m2.x < 50 && m2.x>0 && m2.y > 0 && m2.y < 50)
						{
							break;
						}
					}
				}
			}
		}

	}
}
int main()
{
	minePlan.kind = 1;//默认为1号机
	D://返回主菜单
	t1 = t2 = t3 = t4 = t5 = t6 = t7 = t8 = GetTickCount();//获取系统开机到当前所经过的毫秒数
	//图形化窗口
	initgraph(WIDTH, HEIGHT);
	//地图
	image(&map1, &minePlan);
	mciSendString("open startMusic.mp3 alias start", NULL, 0, NULL);//alias 起别为 mymusic;
	mciSendString("play start repeat", NULL, 0, NULL);
	putimage(0, 0, &map[0]);
	FlushBatchDraw();
	//主菜单
	if (MainMenu() == 0)//在主菜单中选择退出游戏时,结束游戏
		return 0;
	R://游戏重新开始
	image(&map1, &minePlan);
	mciSendString("close start ", NULL, 0, NULL);
	mciSendString("close time ", NULL, 0, NULL);
	mciSendString("open 倒计时.wav alias time", NULL, 0, NULL);//倒计时音乐
	mciSendString("play time ", NULL, 0, NULL);
	int jishu=3;
	while (jishu>0)//游戏开始倒计时
	{
		putimage(0, 0, &map1);
		putimage(300, 350, 17, 22, &shuziyama[0], jishu * 17, 0, NOTSRCERASE);
		putimage(300, 350, 17, 22, &shuzi[0], jishu * 17, 0, SRCINVERT);
		FlushBatchDraw();
		Sleep(1000);
		jishu--;
	}
	putimage(280, 350, &tubiao[5], NOTSRCERASE);
	putimage(280, 350,&tubiao[4], SRCINVERT);
	FlushBatchDraw();
	Sleep(1000);
	mciSendString("close start ", NULL, 0, NULL);
	mciSendString("open ll.mp3 alias mymusic", NULL, 0, NULL);//alias 起别为 mymusic;
	mciSendString("play mymusic repeat", NULL, 0, NULL);
	while (1)
	{
		BeginBatchDraw();//开启双缓冲绘图,在内存中画好,再显示出来
		int b = keyDown(&map1, 10);
		drowGame();	//更新当前的地图,飞机,子弹,重复执行子弹移动的函数,实现子弹的移动
		if (b == 1)//退出游戏
		{
			mciSendString("stop mymusic", NULL, 0, NULL);//关掉背景音乐
			PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);//关掉子弹音效
			break;
		}
		else if (b == 2)//暂停
		{
			if (timeout() == 1)//返回1,代表返回主菜单
			{
				mciSendString("stop mymusic", NULL, 0, NULL);//关掉背景音乐
				goto D;
			}
		}
		else if (b == 3)//我方死亡,boss死亡
		{
			mciSendString("stop mymusic", NULL, 0, NULL);//关掉背景音乐
			PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);//关掉子弹音效
			break;
		}
		FlushBatchDraw();
		Sleep(20);//延时函数
	}
	//判断游戏结束后的选择
	DataConserve();//每次退出游戏界面后保存数据
	char how;
	how = GameOver();//游戏结束结束界面的选择
	if (how == 'D')
		goto D;
	else if (how == 'R')
		goto R;
	return 0;
}

AirGame.cpp

#define _CRT_SECURE_NO_WARNINGS
#include"airHead.h"
#pragma comment(lib,"Winmm.lib")//导入Winmm.lib库,让歌曲可以播放

//图片加载函数
extern int s = 0;//boss选择
extern IMAGE map1, mine[2], map[7] ,tubiao[10], shuzi[3], shuziyama[3];//声明外部变量
extern Role minePlan ;				//定义我方飞机
Ico ico[5], danger;					//danger危险图标,ico图标
Enemy enemyPlan[NUM], boss[2];		//定义敌方飞机
Bullte  bullet[N], enemyBult[N], BossBul[BOSSBUL], developBul[15], shell ;	//定义我方和地方子弹、炮弹
extern DWORD t1, t2,t3,t4, t5, t6,t7,t8;
IMAGE enemybul,blood[2],jineng[15],jinengyanma[15],img_developBul[15], boom2[2], boom2yanma[2],cue[2],bomb[2],hudun,relive, war[15], waryanma[15], enemy[10]; //relive提示复活的图片
IMAGE  boom[11], boomyanma[11], zidan, minebit[2];//爆炸、子弹、飞机掩码
extern IMAGE enemy2[5], enemy2yanma[5];//旋转的敌机
int m = 160, BloodWidth = -10, time[7] , show = 1;//dazao = 0,
int x = 0,jj=0,enemy_x=-1,enemy_y=-1,speedx=2,speedy=2;//enemy_x确定敌机爆炸的位置,speedx确定升级图标的移动速度
int score = 10;//击杀一定数量的敌机,boss出现,
extern int Num[7],count, img_x, img_y;
int fen = score / 2,num_death_enemy;
int ene_2 = 0,my_2;//my_2飞机图片选择,ene_2旋转敌机图片选择
int px[2] ,condition=0;//condition判断无敌状态,px用于地图移动
void image(IMAGE* map1, Role* minePlan)
{
	loadimage(&map[0], "feng.jpg", WIDTH, HEIGHT);//封面图片
	loadimage(&mine[0], "mp.JPG", 50, 50);//自身飞机
	loadimage(&minebit[0], "mpbit.jpg", 50, 50);
	loadimage(&minebit[1], "minePlan22.png");//二号飞机
	loadimage(&mine[1], "minePlan2.png");
	loadimage(map1, "map1.jpg", 600, 700);//地图1
	loadimage(&map[1], "map22.jpg", 600, 700);
	loadimage(&map[2], "gameEnd.jpg", 600, 700);
	loadimage(&map[3], "map3.jpg", 600, 1140);
	loadimage(&map[4], "map3.jpg", 600, 1140);
	loadimage(&map[5], "型号.png");
	loadimage(&map[6], "jilu.jpg");
	loadimage(&zidan, "zidan1.png",40,50);//子弹
	loadimage(&enemybul, "enemyBul.png", 20, 50);//敌军子弹
	loadimage(&enemy[0], "enemy1.jpg", 60, 60);//敌机掩码图
	loadimage(&enemy[1], "enemy1_1.jpg", 60, 60);
	loadimage(&enemy[2], "diji2.png", 70, 50);
	loadimage(&enemy[3], "diji22.png", 70, 50);//敌机掩码
	loadimage(&enemy[4], "diji1.png", 200, 150);//boss
	loadimage(&enemy[5], "diji11.png", 200, 150);//boss掩码
	loadimage(&enemy[6], "diji4.png", 60, 60);
	//炸弹
	loadimage(&bomb[0], "enemy\\paodan1.png");
	loadimage(&bomb[1], "enemy\\paodan11.png");

	loadimage(&img_developBul[0], "updata11.png", 20, 60);//升级子弹掩码
	loadimage(&img_developBul[1], "updata.png", 20, 60);
	//暂停提示图片
	loadimage(&cue[0], "zanting.png",600,700);
	//获取图标
	loadimage(&tubiao[0], "fanhui11.png", 50, 50);//掩码图,返回图标
	loadimage(&tubiao[1], "fanhui.png", 50, 50);
	loadimage(&tubiao[2], "12531.png", 50, 30);//掩码,升级图标
	loadimage(&tubiao[3], "1253.png", 50, 30);
	
	loadimage(&relive, "tishi.png");

	loadimage(&tubiao[6], "enemy\\weixian11.png", 50, 50);//危险图标掩码
	loadimage(&tubiao[7], "enemy\\weixian1.png", 50, 50);
	//护盾
	loadimage(&hudun, "didang.png", 90, 90);
	//技能效果
	for (int i = 0; i < 6; i++)//这种方式可以获取多张图片,减少代码量
	{
		char str[50] = "";
		sprintf_s(str, "texiao\\dian%d.jpg", i + 1);
		loadimage(&war[i], str, 60, 700);
		sprintf_s(str, "texiao\\dian1%d.jpg", i + 1);
		loadimage(&waryanma[i], str, 60, 700);
	}
	//敌人2
	loadimage(&enemy2yanma[0], "enemy\\speed_enemy11.png");
	loadimage(&enemy2[0], "enemy\\speed_enemy.png");
	
	loadimage(&blood[0], "blood1.png", 300, 20);//boss血量
	loadimage(&blood[1], "blood2.png", 300, 20);

	//获取数字
	loadimage(&shuzi[0], "shuzi.png");
	loadimage(&shuziyama[0], "shuzi11.png");
	loadimage(&tubiao[4], "kaishi.png", 70, 30);
	loadimage(&tubiao[5], "kaishi11.png", 70, 30);
	//爆炸图片
	for (int i = 0; i < 11; i++)
	{
		char str[50] = "";
		sprintf_s(str, "texiao\\bbb%d.png", i + 1);
		loadimage(&boom[i], str, 100, 100);
		sprintf_s(str, "texiao\\bbby%d.png", i + 1);
		loadimage(&boomyanma[i], str, 100, 100);
	}
	//爆炸2
	loadimage(&boom2[0], "texiao\\爆炸11.png", 600, 600);//boss爆炸
	loadimage(&boom2yanma[0], "texiao\\爆炸111.png", 600, 600);
	loadimage(&boom2[1], "texiao\\爆炸11.png");//我方飞机爆炸
	loadimage(&boom2yanma[1], "texiao\\爆炸111.png");

	loadimage(&jineng[0], "jineng.png", 40, 30);//技能
	loadimage(&jineng[1], "hudun.png", 70, 70);

	BloodWidth = -10;
	//初始图标不存在
	ico[0].live = 0;
	//初始化自身位置
	minePlan->x = WIDTH/2;
	minePlan->y = 500;
	minePlan->live = 1;
	minePlan->type = 1;//子弹种类
	minePlan->score = 0;
	//初始化一部分数据
	time[0]=-1;
	time[1] = 0;
	time[2] = 0;
	time[3] = 0;
	show = 1;
	//初始化升级图标出现的时候
	num_death_enemy = 0;//击杀敌方飞机数量
	fen = score / 2;
	m = 160;//boss移动
	count = 0;//初始化存数字的数组下标
	condition = 0;//初始护盾不存在
	//初始化炮弹数据
	shell.live = 0;//初始炮弹不存在
	shell.shot = 0;
	shell.y = 0;
	//初始化子弹数据
	for (int i = 0; i < N; i++)
	{	
		developBul[i].live = 0;//表示没有子弹
		bullet[i].live = 0;//表示没有子弹
	}
	//初始化敌军子弹
	for (int i = 0; i < N; i++)
	{
		enemyBult[i].live = 2;//给所有子弹上塘,所有敌军共用一个子弹库
		enemyBult[i].y = -50;
		enemyBult[i].x = 0;
	}
	//多个敌军是,可以单独写个函数,传递参数i,根据概率产生敌军的种类,默认越厉害,概率越低
	for (int i = 0; i < NUM; i++)
	{
		enemyPlan[i].live = 0;//所有不存活
		enemyPlan[i].HP = 1;
		enemyPlan[i].shot = 'N';//表示敌机未曾发射过子弹;
	}
	//初始化boss数据;
	boss[s].HP = 100;
	boss[s].type = 3;
	boss[s].live = 1;
	boss[s].x =50;
	boss[s].y = 0;
	//初始boss子弹库
	for (int i = 0; i < BOSSBUL; i++)
		BossBul[i].live = 1;//表示有子弹,2表示子弹已发射
}
//创建线程执行的代码函数       // CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)BOOM, NULL, NULL, 0);//调用线程
DWORD WINAPI BOOM(LPVOID arg)//爆炸音效线程 //DWORD是无符号整,相当于C中的数据类型//一个返回DWORD 的API函数//
{
	mciSendString("close boom", 0, 0, 0);
	mciSendString("open Bomb.wav alias boom", 0, 0, 0);
	mciSendString("play boom", 0, 0, 0);
	return 0;
}
DWORD WINAPI tttt(LPVOID arg)//大招音效释放线程
{
	mciSendString("open dazao123.mp3 alias jineng", 0, 0, 0);
	mciSendString("play jineng ", 0, 0, 0);
	return 0;
}
//多线程爆炸动画,有闪烁的问题,暂未使用
DWORD WINAPI planBoom(LPVOID arg)//爆炸效果线程
{
	while (x<11)
	{
		putimage(enemy_x, enemy_y, &boomyanma[x], NOTSRCERASE);
		putimage(enemy_x, enemy_y, &boom[x], SRCINVERT);
		FlushBatchDraw();
		Sleep(200);
		x++;
		if (x == 11)
		{
			x = 7;
			break;
		}
	}
	return 0;
}
//图标升级
void up()
{
	ico[0].x = enemy_x;//图标的位置等于爆炸的飞机的坐标
	ico[0].y = enemy_y;
	ico[0].live = 1;
}
int  Datadir()
{
	FILE* fp;
	if ((fp = fopen("GameData\\data.text", "r")) == NULL)
	{
		return -1;
	}
	char str[10];
	fgets(str,9, fp);//获取历史记录
	int num_str;
	num_str = atoi(str);//将字符串转为整型
	fclose(fp);
	return num_str;
}
void showEnemy2(int enemyPlan_x,int enemyPlan_y)//打印旋转敌机
{
	switch (ene_2)
	{
	case 0:
		putimage(enemyPlan_x, enemyPlan_y, 47, 58, &enemy2yanma[0], 2, 0, NOTSRCERASE);
		putimage(enemyPlan_x, enemyPlan_y, 47, 58, &enemy2[0], 2, 0, SRCINVERT);
		break;
	case 1:
		putimage(enemyPlan_x, enemyPlan_y, 38, 58, &enemy2yanma[0], 49, 0, NOTSRCERASE);
		putimage(enemyPlan_x, enemyPlan_y, 38, 58, &enemy2[0], 49, 0, SRCINVERT);
		break;
	case 2:
		putimage(enemyPlan_x, enemyPlan_y, 20, 58, &enemy2yanma[0], 88, 0, NOTSRCERASE);
		putimage(enemyPlan_x, enemyPlan_y, 20, 58, &enemy2[0], 88, 0, SRCINVERT);
		break;
	case 3:
		putimage(enemyPlan_x, enemyPlan_y, 20, 58, &enemy2yanma[0], 108, 0, NOTSRCERASE);
		putimage(enemyPlan_x, enemyPlan_y, 20, 58, &enemy2[0], 108, 0, SRCINVERT);
		break;
	case 4:
		putimage(enemyPlan_x, enemyPlan_y, 40, 58, &enemy2yanma[0], 128, 0, NOTSRCERASE);
		putimage(enemyPlan_x, enemyPlan_y, 40, 58, &enemy2[0], 128, 0, SRCINVERT);
		break;
	}
}
void showMyPlan(int my_x, int my_y)//自身飞机二号
{
	switch (my_2)
	{
	case 0:
		putimage(my_x, my_y, 53, 87, &minebit[1], 0, 0, NOTSRCERASE);
		putimage(my_x, my_y, 53, 87, &mine[1], 0, 0, SRCINVERT);
		break;
	case 1:
		putimage(my_x, my_y, 65, 87, &minebit[1], 53 ,0, NOTSRCERASE);
		putimage(my_x, my_y, 65, 87, &mine[1], 53, 0, SRCINVERT);
		break;
	case 2:
		putimage(my_x, my_y, 78, 87, &minebit[1], 118, 0, NOTSRCERASE);
		putimage(my_x, my_y, 78, 87, &mine[1], 118, 0, SRCINVERT);
		break;
	case 3:
		putimage(my_x, my_y, 67, 87, &minebit[1], 196, 0, NOTSRCERASE);
		putimage(my_x, my_y, 67, 87, &mine[1], 196, 0, SRCINVERT);
		break;
	case 4:
		putimage(my_x, my_y, 55, 87, &minebit[1], 263, 0, NOTSRCERASE);
		putimage(my_x, my_y, 55, 87, &mine[1], 263, 0, SRCINVERT);
		break;
	}
}
//创建子弹,给子弹补给
void createbullet()
{	//循环给子弹赋值,及充满子弹
	if (time[0] >= 5000 || time[0] == -1)//当技能释放完打印子弹,或者未释放技能时
	{
		for (int i = 0; i < N; i++)
		{
			if (bullet[i].live == 0)
			{
				bullet[i].live = 1;//表示有子弹,未发射;每调用一次只会产生一个子弹
				//获取当前飞机的位置,把值赋值给子弹
				if (minePlan.kind == 1)//飞机1
					bullet[i].x = minePlan.x + 6;
				else                    //飞机2
					bullet[i].x = minePlan.x + 20;
				bullet[i].y = minePlan.y;
				break;//一次只发射一颗子弹;所以break结束循环
			}
		}
		if (minePlan.type == 2)
		{
			if (time[3] == 40)
			{
				for (int i = 0; i < N; i += 2)//创建副武器子弹
				{
					if (developBul[i].live == 0 && i + 2 <= 15)//子弹不存在,
					{
						developBul[i].live = 1;
						developBul[i + 1].live = 1;
						developBul[i].x = minePlan.x - 20;
						developBul[i].y = minePlan.y;
						if (minePlan.kind == 2)
							developBul[i + 1].x = minePlan.x + 70;
						else
							developBul[i + 1].x = minePlan.x + 50;
						developBul[i + 1].y = minePlan.y;
						break;
					}
				}
			}
			time[3] += 20;
			if(time[3] > 40)
			{
				time[3] = 0;
			}
		}
	}
	//实时获取存在的敌军的位置,将位置赋值给敌军子弹
	//先创建子弹,及敌军还未产生,所有子弹均为1;而当产生第一架敌机,所有的
	for (int i = 0; i < NUM; i++)
	{
		if (enemyPlan[i].live == 1&&enemyPlan[i].shot=='N')
		{
			for (int j = 0; j < N; j++)
			{
				if (enemyBult[j].live == 2)//若果子弹库还有子弹。给改存活的敌军发射一颗子弹,每架飞机只发射一个
				{
					enemyBult[j].x = enemyPlan[i].x + 15;
					enemyBult[j].y = enemyPlan[i].y + 45;
					enemyBult[j].live = 1;
					enemyPlan[i].shot = 'Y';
					break;
				}
			}
		}
	}
	//补充敌军子弹库
	for (int i = 0; i < N; i++)
	{
		if (enemyBult[i].y > HEIGHT)
		{
			enemyBult[i].live = 2;
		}
	}
	//产生boss子弹
	if (num_death_enemy>= score)//当大于100时进行子弹的填充
	{
		for (int i = 0; i < BOSSBUL; i = i + 4)
		{
			if (BossBul[i].live == 1)
			{
				BossBul[i].live = 2;
				BossBul[i + 1].live = 2;
				BossBul[i + 2].live = 2;
				BossBul[i + 3].live = 2;
				BossBul[i].y = boss[s].y + 100;//当前boss[s].y=50,所以加上100才是飞机的顶端
				BossBul[i + 1].y = boss[s].y + 100;//将最新的飞机坐标给子弹
				BossBul[i + 2].y = boss[s].y + 100;
				BossBul[i + 3].y = boss[s].y + 100;
				BossBul[i].x = boss[s].x+60;
				BossBul[i + 1].x = boss[s].x+80;
				BossBul[i + 2].x = boss[s].x+100;
				BossBul[i + 3].x = boss[s].x+120;
				break;
			}
		}
	}
	//创建炮弹
	if (rand() % 10 < 1&&shell.live==0&&num_death_enemy>=10)
	{
		shell.live = 1;
		shell.shot = 0;
		shell.y = -150;//防止在出现危险警告时,导弹在屏幕上未显示,但存在,使飞机碰到死亡
	}
}
//产生敌机
void createEnemy()
{
	if (num_death_enemy >= score)//boss出现
	{
		for (int i = 0; i < NUM; i++)//将所有敌军变为0;
		{
			if (enemyPlan[i].live == 1)
			{
				enemyPlan[i].live = 0;
			}
		}
	}
	else 
	{
		for (int i = 0; i < NUM; i++)
		{	//第一个敌机一定能产生出来
			if (enemyPlan[0].live == 0)
			{
				enemyPlan[0].live = 1;//将敌机创造出来
				enemyPlan[0].x = rand() % (WIDTH - 70);//x位置随机在0-530、width=600
				enemyPlan[0].y = 0;
				enemyPlan[0].HP = 1;
				enemyPlan[0].type = 1;
				break;
			}//当第一个敌机存在时,开始判断下一个敌机												
			else if (enemyPlan[i + 1].live == 0 && (i + 1) < NUM && (rand() % 10 < 7))//(i+1)<NUM不让行索超过最大值,当下一个没有产生敌军时,就结束循环												
			{
				if (rand() % 10 < 4)//创造成功的概率只创建一个敌机,种类一
				{
					enemyPlan[i + 1].live = 1;//将敌机创造出来
					enemyPlan[i + 1].x = rand() % (WIDTH - 70);
					enemyPlan[i + 1].y = 0;
					enemyPlan[i + 1].HP = 1;
					enemyPlan[i + 1].type = 1;
					break;
				}
				else if (rand() % 10 < 2)//敌机种类二
				{
					enemyPlan[i + 1].live = 1;//将敌机创造出来
					enemyPlan[i + 1].x = rand() % (WIDTH - 70);//x坐标
					enemyPlan[i + 1].y = 0;
					enemyPlan[i + 1].HP = 5;
					enemyPlan[i + 1].type = 2;
					break;
				}
				else if (rand() % 10 < 5)//第三种敌机
				{
					enemyPlan[i + 1].live = 1;//将敌机创造出来
					enemyPlan[i + 1].x = rand() % (WIDTH - 70);//x坐标
					enemyPlan[i + 1].y = 0;
					enemyPlan[i + 1].HP = 3;
					enemyPlan[i + 1].type = 3;
					break;
				}
				break;
			}
		}
	}
}
void enemyMove(int speed) 
{
	//boss的移动
	if(num_death_enemy >= score)
	{	//进行自由的左右来回移动。先想右移动一段距离,再向左移动同样的距离实现,来回移动
		if (boss[s].y < 50)
		{
			boss[s].y += 2;
		}
		if (m>0&&m<=160)//m代表移动的次数,向左移动
		{
			boss[s].x += 2;
			m--;
		}
		if(m<=0)//向右移动。
		{
			boss[s].x -= 2;
			m--;
			if (m == -160)//当移动了与左移动相同的距离,再变回右移动的条件
				m = 160;
		}
	}
	else
	{
		for (int i = 0; i < NUM; i++)
		{
			if (enemyPlan[i].live == 1)//遍历数组,寻找存活的敌军
			{
				if (enemyPlan[i].type == 1) //判断类型,改变不同的速度
				{
					enemyPlan[i].y += speed;	//只需要垂直移动
				}
				else if (enemyPlan[i].type == 2)
				{
					enemyPlan[i].y += speed + 2;
				}
				else if (enemyPlan[i].type == 3)
				{
					enemyPlan[i].y += speed + 1;
				}
				if (enemyPlan[i].y > HEIGHT)//当敌机超过地图时,将live变为0,在创造时,就可以继续使用
				{
					enemyPlan[i].live = 0;
					enemyPlan[i].shot = 'N';//是否发射子弹
				}
			}
		}
	}
}
//子弹发射原理,定义数组,给数组的第一个开始赋予子弹,每按一次,给一颗。通过判定数组是否有子弹进行移动,每个子弹的位置都不一样
										
void bulletMove(int speed)//speed为子弹的移动速度  
{
	for (int i = 0; i < N; i++)//我方子弹移动
	{
		if (bullet[i].live == 1)//子弹存在  一次只有一个子弹有,只移动一次
		{
			bullet[i].y -= speed;//子弹坐标的移动
			if (bullet[i].y <= 0)//当子弹超出范围时又将其值设置为0,补充我军子弹
			{
				bullet[i].live = 0;
			}
		}
		if (developBul[i].live == 1)//副武器
		{
			developBul[i].y -= 8;
			if (developBul[i].y <= 0)//超出屏幕回收
			{
				developBul[i].live = 0;

			}
		}
	}
	if (num_death_enemy < score)//boss未出现
	{
		//敌军子弹的移动,每次移动10个像素
		for (int i = 0; i < N; i++)
		{
			if (enemyBult[i].live == 1)
			{
				enemyBult[i].y += 10;
			}
		}
	}
	
	//boss子弹的移动
	for (int i = 0; i < BOSSBUL; i++)
	{
		if (BossBul[i].live == 2)
		{
			BossBul[i].y += 7;
		}
		if (BossBul[i].y > HEIGHT)//超过屏幕将子弹回收
		{
			BossBul[i].live = 1;
		}
	}
	//当飞机吃到图标时
	if (ico[0].live == 1)
	{
		if ((minePlan.kind == 1 && ico[0].x - minePlan.x > -20 && ico[0].x - minePlan.x < 40 && ico[0].y - minePlan.y<25 && ico[0].y - minePlan.y>-40)
			|| (minePlan.kind == 2 && ico[0].y > minePlan.y + 20 && ico[0].y < minePlan.y + 50 && ico[0].x<minePlan.x + 60 && ico[0].x > minePlan.x))
		{
			//当飞机1号吃到图标,图标消失,飞机子弹增加副武器
			ico[0].live = 0;
			minePlan.type = 2;
		}
	}
 //图标的移动
 if (ico[0].live == 1)
 {
	 ico[0].x += speedx;//移动慢一点
	 ico[0].y += speedy;//移动慢一点
	 if (ico[0].x <= 0 || ico[0].x >= 570)
		 speedx = -speedx;
	 if (ico[0].y >= 670 || ico[0].y <= 0)
		 speedy = -speedy;
 }
 //炮弹移动
 if (shell.live == 1&&shell.shot==1)//存在且发射出去才移动
 {
	 shell.y +=15;
	 if (shell.y > 700)
	 {
		 shell.live = 0;
		 shell.shot = 0;
		 shell.y = -150;
	 }
 }
}
int minePlayDeath()
{
	mciSendString("pause mymusic", NULL, 0, NULL);//暂停背景音乐
	PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)BOOM, NULL, NULL, 0);//播放爆炸
	mciSendString("close death ", NULL, 0, NULL);//死亡音效
	mciSendString("open 死亡.mp3 alias death", NULL, 0, NULL);
	mciSendString("play death ", NULL, 0, NULL);
	minePlan.live = 0;//飞机死亡
	for (int i = 0;i<4; i++)//通过二维数组来实现爆炸效果
	{
		for (int j = 0;j<4; j++)
		{
			drowGame();
			putimage(minePlan.x, minePlan.y, 64, 64, &boom2yanma[1], j * 64, i * 64,NOTSRCERASE);
			putimage(minePlan.x, minePlan.y, 64, 64, &boom2[1], j * 64, i * 64, SRCINVERT);
			FlushBatchDraw();
			Sleep(100);
		}
	}
	putimage(126,312,&relive, SRCPAINT);
	FlushBatchDraw();
	system("pause");
	while (1)//选择死亡后是否复活
	{
		if (_getch() == 'x')//按下键复活
		{
			mciSendString("resume mymusic", NULL, 0, NULL);
			minePlan.x = WIDTH / 2;
			minePlan.y = 500;
			minePlan.live = 1;
			condition = 1;
			return 1;
		}
		else
		{
			minePlan.live = 0;
			return 0;
		}
	}
	//return 0;
}
int bossDeath()
{
	boss[s].live = 0;
	for (int i = 0; i < BOSSBUL; i++)
	{
		BossBul[i].live = 0;
	}
	PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);//关闭子弹音效
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)BOOM, NULL, NULL,0);//播放爆炸
	mciSendString("close victory ", NULL, 0, NULL);				//胜利音效
	mciSendString("open 胜利.mp3 alias victory", NULL, 0, NULL);
	mciSendString("play victory ", NULL, 0, NULL);
	for (int i = 0; i < 4; i++)//通过二维数组来实现爆炸效果
	{
		for (int j = 0; j < 4; j++)
		{
			drowGame();//刷新地图中的其他图片
			putimage(boss[s].x, boss[s].y, 150, 150, &boom2yanma[0], j * 150, i * 150, NOTSRCERASE);
			putimage(boss[s].x, boss[s].y, 150, 150, &boom2[0], j * 150, i * 150, SRCINVERT);
			FlushBatchDraw();
			Sleep(150);
		}
	}
	return 0;
}
void Score(int i)
{
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)BOOM, NULL, NULL, 0);//敌机爆炸音效线程
	enemy_x = enemyPlan[i].x;//记录敌机爆炸的位置,给敌机爆炸效果定位
	enemy_y = enemyPlan[i].y;
	enemyPlan[i].shot = 'N';
	enemyPlan[i].live = 0;//敌人死亡
	num_death_enemy++;//统计死亡敌机数
	if (enemyPlan[i].type == 1)//判断敌机类型增加分数
		minePlan.score += 10;
	else if (enemyPlan[i].type == 2)
		minePlan.score += 30;
	else if (enemyPlan[i].type == 3)
		minePlan.score += 20;
}
int deadth()//判断死亡
{
	if (num_death_enemy >= score)//boss出现
	{
		//打中boss的判断
		for (int i = 0; i < N; i++)
		{
			if (bullet[i].live == 1)//表示已发射的子弹
			{
				if (bullet[i].x - boss[s].x > 0 && bullet[i].x - boss[s].x < 170 && bullet[i].y - boss[s].y < 130 && bullet[i].y - boss[s].y>5)
				{
					bullet[i].live = 0;
					boss[s].HP -= 1;
					BloodWidth -= 3;//boss血量条图片的宽度减少
					if (boss[s].HP <= 0)//boss血量为小于0时
					{
						return bossDeath();
					}
				}
			}
			//副武器判断
			if (developBul[i].live == 1)
			{
				if (developBul[i].x - boss[s].x > 50 && developBul[i].x - boss[s].x < 170 && developBul[i].y - boss[s].y < 130 && developBul[i].y - boss[s].y>5)
				{
					boss[s].HP -= 2;
					BloodWidth -= 6;
					developBul[i].live = 0;
					if (boss[s].HP <= 0)//boss血量为0时
						return bossDeath();
				}
			}
		}
		//boss子弹击中我方
		if (condition != 1)//为1飞机处于无敌状态
		{
			for (int i = 0; i < BOSSBUL; i++)
			{
				if (BossBul[i].live == 2)//已发射的子弹
				{
					if ((minePlan.kind == 1 && BossBul[i].x - minePlan.x > -5 && BossBul[i].x - minePlan.x < 45 && BossBul[i].y - minePlan.y>5 && BossBul[i].y - minePlan.y < 50)
						|| (minePlan.kind == 2 && BossBul[i].x - minePlan.x > -5 && BossBul[i].x - minePlan.x < 65 && BossBul[i].y - minePlan.y>15 && BossBul[i].y - minePlan.y < 70))//被boss子弹击中
					{
						
						return minePlayDeath();
					}
				}
			}
		}
		//我方与boss碰撞
		if ((minePlan.kind == 1 && boss[s].x < minePlan.x -20 && boss[s].x+200 > minePlan.x-50 && boss[s].y +100> minePlan.y && boss[s].y+20< minePlan.y)
			|| (minePlan.kind == 2 && boss[s].x < minePlan.x - 30 && boss[s].x + 200 > minePlan.x - 50 && boss[s].y + 100 > minePlan.y&& boss[s].y + 20 < minePlan.y))//被boss子弹击中)
		{
			return minePlayDeath();
		}
	}
	else//boss未出现
	{
		for (int i = 0; i < NUM; i++)
		{
			if (enemyPlan[i].live == 1)//寻找存活的敌机
			{
				for (int j = 0; j < N; j++)//遍历子弹,判断子弹是否命中该存活敌机
				{	//子弹击中敌机,子弹归0,PH=0敌机死亡;
					if (bullet[j].live == 1)//若果子弹已发射
					{
						if (bullet[j].x - enemyPlan[i].x > -15 && bullet[j].x - enemyPlan[i].x < 40 && bullet[j].y - enemyPlan[i].y < 45 && bullet[j].y - enemyPlan[i].y>5)
						{
							enemyPlan[i].HP = enemyPlan[i].HP - 1;
							bullet[j].live = 0;
							if (enemyPlan[i].HP <= 0)
							{	
								Score(i);//播放敌机爆炸音效并记录分数
							}
						}
					}
				}
				for (int j = 0; j < N; j++)//副武器打中敌机
				{
					if (developBul[j].live == 1)//已发射的子弹
					{
						if (developBul[j].x - enemyPlan[i].x > -5 && developBul[j].x - enemyPlan[i].x < 45 && developBul[j].y - enemyPlan[i].y>5 && developBul[j].y - enemyPlan[i].y < 45)//被boss子弹击中
						{
							enemyPlan[i].HP = enemyPlan[i].HP - 2;
							developBul[j].live = 0;
							if (enemyPlan[i].HP <= 0)
							{	
								Score(i);
							}
						}
					}
				}
				
				if (condition != 1)
				{		//当己方飞机碰到敌方飞机时死亡
					if ((minePlan.kind == 1 && abs(minePlan.x - enemyPlan[i].x) < 40 && abs(minePlan.y - enemyPlan[i].y) < 40)
						|| (minePlan.kind == 2 && enemyPlan[i].y > minePlan.y&& enemyPlan[i].y < minePlan.y + 60 && enemyPlan[i].x > minePlan.x - 20 && enemyPlan[i].x < minePlan.x + 65))//abs取整数绝对值
					{
						//outtextxy(minePlan.x, minePlan.y, "双击x复活,按z结束游戏")
						return minePlayDeath();
						
					}
				}
				
			}
			
		}

		//我方被敌方子弹击中死亡
		if (condition != 1)
		{
			for (int i = 0; i < N; i++)//遍历敌方子弹判断是否存活
			{
				if (enemyBult[i].live == 1)
				{
					if ((minePlan.kind == 1 && enemyBult[i].x - minePlan.x > 5 && enemyBult[i].x - minePlan.x < 30 && enemyBult[i].y - minePlan.y>5 && enemyBult[i].y < minePlan.y + 40)
						|| (minePlan.kind == 2 && enemyBult[i].x - minePlan.x > -5 && enemyBult[i].x - minePlan.x < 65 && enemyBult[i].y - minePlan.y>15 && enemyBult[i].y - minePlan.y < 70))
					{//子弹击中我方时
						//enemyBult[i].live = 0;
						//enemyBult[i].y = -50;
						return  minePlayDeath();
					}
				}
			}
			
		}
	}
	if (time[0] < 5000 && time[0] >= 0)//技能正在释放的时候
	{
		for (int i = 0; i < NUM; i++)//判断敌机是否有存活的
		{
			if (enemyPlan[i].live == 1)
			{
				if (minePlan.x - enemyPlan[i].x < 40 && minePlan.x - enemyPlan[i].x > -50&&minePlan.y>enemyPlan[i].y )//技能击中敌机
				{
					enemyPlan[i].HP -= 3;//血量减三
					if (enemyPlan[i].HP <= 0)
					{
						Score(i);
					}
				}
			}
		}
		if (num_death_enemy >= score)
		{
			if (minePlan.x - boss[s].x < 175 && minePlan.x - boss[s].x > -75 && minePlan.y > boss[s].y)//技能击中敌机
			{
				boss[s].HP -= 1;
				BloodWidth -= 3;//boss血量条图片的宽度减少
				if (boss[s].HP <= 0)//boss血量为0时
				{
					return bossDeath();
				}
			}
		}
	}
	if (num_death_enemy == fen)//当敌机死亡数达到指定时 //调用产生图标的函数
	{
		up();
		fen -= 1;//若果不减,并且敌机死亡数不增加,则图标不会移动
	}
	//炮弹撞上飞机
	if (condition != 1)
	{
		if ((minePlan.kind == 1 && shell.x > minePlan.x - 50 && shell.x<minePlan.x + 30 && shell.y>minePlan.y - 110 && shell.y < minePlan.y + 20)
			|| (minePlan.kind == 2 && shell.x > minePlan.x - 50 && shell.x<minePlan.x + 45 && shell.y > minePlan.y - 110 && shell.y < minePlan.y + 60))
		{
			return  minePlayDeath();
		}
	}
	return 1;
}
char GameOver()//游戏结束后
{
	PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);//停止子弹音乐
	mciSendString("pause mymusic", NULL, 0, NULL);//停止背景音乐
	count = 0;//数组下标初始化为零
	putimage(0, 0, &map[2]);//打印图片
	img_x = 210;
	img_y = 275;
	OutScore(minePlan.score);//输出分数
	img_x = 210;
	img_y = 155;
	OutScore(num_death_enemy);//输出击杀数量
	FlushBatchDraw();
	MOUSEMSG end_mouse;
	while (1)
	{
		end_mouse = GetMouseMsg();
		if (end_mouse.uMsg == WM_LBUTTONDOWN)//左键点下
		{
			if (end_mouse.x > 146 && end_mouse.x < 435 && end_mouse.y < 626 && end_mouse.y>550)//返回主菜单
			{
				return 'D';
			}
			if (end_mouse.x > 146 && end_mouse.x < 435 && end_mouse.y < 466 && end_mouse.y>390)//重新开始游戏
			{
				return 'R';
			}
		}
	}
	return 0;
}
int timeout()//暂停
{
	//putimage(140, 165, &cue[0]);
	putimage(0, 0, &cue[0]);
	FlushBatchDraw();
	mciSendString("pause mymusic", NULL, 0, NULL);//暂停背景音乐
	PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);//暂停子弹音效
	MOUSEMSG n;//定义鼠标变量
	while (1)
	{
		while (MouseHit())
		{
			n = GetMouseMsg();
			if (n.uMsg == WM_LBUTTONDOWN)
			{
				if (n.x > 190 && n.x < 410 && n.y> 243 && n.y < 320)//点击继续
				{
					mciSendString("resume mymusic", NULL, 0, NULL);
					return 0;
				}
				else if (n.x > 190 && n.x < 410 && n.y> 400 && n.y < 481 )//点击退出,返回主菜单
				{
					return 1;
				}
			}
		}
	}
}
//保存游戏数据,保存数据并退出
void DataConserve()
{
	FILE* fp1;
	FILE* fp;//定义文件指针
	char str[10];
	int num_str;
	if ((fp1 = fopen("GameData\\data.text", "r")) == NULL);
	else
	{
		fgets(str, 9, fp1);//获取历史记录
		num_str = atoi(str);//将字符串转为整型
	}
	fclose(fp1);
	if ((fp = fopen("GameData\\data.text", "w+")) == NULL)//打开或创建文件失败时,fopen会返回NULL,成功则返回文件的首地址
	{
		exit(1);//退出程序
	}
	_itoa_s(minePlan.score>num_str?minePlan.score:num_str, str, 10);//后面的10是装换的进制数,不能跨平台,跨平台需使用sprintf_s();
	fputs(str, fp);//将数据保存
	fclose(fp);//关闭文件指针
}
void OutScore(int number)//在指定地方输出数字图片
{
	if (number / 10 != 0)//不是个位数
	{
		OutScore(number / 10);
		Num[count++] = number % 10;
	}
	else//是各位数,每次输出只会执行一次,开始为个位数或者分解到最后运行一次,
	{
		Num[count++] = number;
	}
	putimage(img_x, img_y, 17, 22, &shuziyama[0], Num[count-1] * 17, 0, NOTSRCERASE);
	putimage(img_x, img_y, 17, 22, &shuzi[0], Num[count - 1] * 17, 0, SRCINVERT);
	img_x += 17;//改变图片的x坐标
}
//画出游戏图片
void drowGame()
{
		putimage(0, 0, &map1);//打印出地图
		//putimage(0, 0, 600, 700, &map[3], 0, px[0]++);//动态地图
		//if (px[0] >= 440)
			// = 0;
		//putimage(0, 700 - (px[0] - 400), 600, 700, &map[3], 0, 0);
		if (minePlan.kind == 1&&minePlan.live==1)//判断飞机类型打印相应的图片
		{
			putimage(minePlan.x, minePlan.y, &minebit[0], NOTSRCERASE);
			putimage(minePlan.x, minePlan.y, &mine[0], SRCINVERT);
		}
		else if(minePlan.kind == 2 && minePlan.live == 1)
		{
			 if (GetKeyState(VK_LEFT) < 0 )//判断移动的方向打印图片
				 my_2 = 3;
			else if (GetKeyState(VK_RIGHT) < 0 )
				 my_2 = 1;
			else
				 my_2 = 2;
			showMyPlan(minePlan.x, minePlan.y);//飞机2号
		}
		
	//打印子弹
		if (time[0] >= 5000 || time[0] == -1)//当技能释放完打印子弹,或者未释放技能时
		{
			if (time[1] >= 1500 || time[1] == 0)//
			{
				for (int i = 0; i < N; i++)
				{
					if (bullet[i].live == 1)
					{
						putimage(bullet[i].x, bullet[i].y, &zidan, SRCPAINT);
					}
				}
			}
		}
	
	//打印分数
	//char k[15];
	//_itoa_s(minePlan.score, k, 10);//将数字转为字符串
	//outtextxy(400, 50, k );//打印int类型有问题,打印字符串没问题
	count = 0;
	img_x = 456;
	img_y = 20;
	OutScore(minePlan.score);
	if (num_death_enemy >= score&&boss[s].live==1)//打印boss,和boss子弹
	{
		//BloodWidth = BloodWidth + 20;
		putimage(boss[s].x, boss[s].y, &enemy[5], NOTSRCERASE);
		putimage(boss[s].x, boss[s].y, &enemy[4], SRCINVERT);
		for (int i = 0; i < BOSSBUL; i++)
		{
			if (BossBul[i].live == 2)
			{
				putimage(BossBul[i].x , BossBul[i].y, &enemybul, SRCPAINT);
				putimage(BossBul[i].x , BossBul[i].y, &enemybul, SRCPAINT);
				putimage(BossBul[i].x , BossBul[i].y, &enemybul, SRCPAINT);
				putimage(BossBul[i].x , BossBul[i].y, &enemybul, SRCPAINT);
			}
		}
		putimage(-10, 20, &blood[0], SRCPAINT);
		putimage(BloodWidth, 20, &blood[1], SRCPAINT);
		
	}
	else
	{
		//打印敌机
		for (int i = 0; i < NUM; i++)
		{//遍历敌机数组,判断哪些为存活就输出
			if (enemyPlan[i].live == 1)
			{
				if (enemyPlan[i].type == 1)
				{
					putimage(enemyPlan[i].x, enemyPlan[i].y, &enemy[0], NOTSRCERASE);//掩码图
					putimage(enemyPlan[i].x, enemyPlan[i].y, &enemy[1], SRCINVERT);
				}
				else if (enemyPlan[i].type == 2)
				{
					putimage(enemyPlan[i].x, enemyPlan[i].y, &enemy[3], NOTSRCERASE);;//掩码图
					putimage(enemyPlan[i].x, enemyPlan[i].y, &enemy[2], SRCINVERT);
				}
				else if (enemyPlan[i].type == 3)
				{
					showEnemy2(enemyPlan[i].x,enemyPlan[i].y);
					time[4] += 20;
					if (time[4] > 100)
					{
						ene_2 += 1;
						time[4] = 0;
					}
					if (ene_2 >= 5)
						ene_2 = 0;
				}
			}
		}
		//打印敌机子弹
		int num = 0;
		for (int i = 0; i < N; i++)
		{//子弹发射后,live值变为1;表示以发射
			if (enemyBult[i].live == 1)
			{
				putimage(enemyBult[i].x, enemyBult[i].y, &enemybul, SRCPAINT);
			}
		}
	}
	//time[0]用于计算技能释放的时间,time[1]用于计算道具冷却的时间,show用于判断道具是否使用及显示
	//技能释放动画
	if (time[0] < 5000 && time[0] >= 0)//按下技能键,释放技能的时间5秒
	{
		if (t7 - t8 > 50)//多久切换一张图片
		{
			t8 = t7;//t7为当前最新的时间
			jj++;
			if (jj >=6)//当图片输完时,变成第一张循环绘制
			{
				jj = 0;
			}
		}
		t7 = GetTickCount();
		if (minePlan.kind == 1)//判断飞机的种类,计算技能释放的位置
		{
			putimage(minePlan.x - 7, minePlan.y - 700, &waryanma[0], NOTSRCERASE);
			putimage(minePlan.x - 7, minePlan.y - 700, &war[jj], SRCINVERT);
		}
		else
		{
			putimage(minePlan.x+8, minePlan.y - 700, &waryanma[0], NOTSRCERASE);
			putimage(minePlan.x+8, minePlan.y - 700, &war[jj], SRCINVERT);
		}
		FlushBatchDraw();
		time[0] += 20;//计算技能释放的时间;
		time[1] += 20;//计算技能能却的时间
	}
	else if (time[0] >= 5000 && time[0] < 15000)//技能冷却的时间10秒
	{
		time[1] += 20;//计算恢复的时间
	}
	 if (time[1] > 15000)//技能冷却完成
	{
		time[1] = 0;
		time[0] = -1;
		show = 1;
	}
	if(show==1)//展示技能图标
	{
		putimage(10, 500, &jineng[0], SRCPAINT);
	}
	//武器升级1
	for (int i = 0; i < N; i++)
	{
		if (developBul[i].live == 1)//子弹存在才发射
		{
			putimage(developBul[i].x, developBul[i].y, &img_developBul[0], NOTSRCERASE);//掩码
			putimage(developBul[i].x, developBul[i].y, &img_developBul[1], SRCINVERT);
		}
	}
	
	//敌机爆炸效果动画
	if (enemy_x >= 0)
	{
		putimage(enemy_x, enemy_y, &boomyanma[x], NOTSRCERASE);
		putimage(enemy_x, enemy_y, &boom[x], SRCINVERT);
	}
	//控制图片切换的时间
	if (t5 - t6>50)
	{
		t6 = t5;
		x++;
		if (x >= 11)//到最后一张后循环
		{
			x = 7;
			enemy_x = -1;//初始坐标为负值
			enemy_x = -1;
		}
	}
	t5= GetTickCount();

	//显示升级图标
	if (ico[0].live == 1)
	{
		putimage(ico[0].x, ico[0].y, &tubiao[2], NOTSRCERASE);
		putimage(ico[0].x, ico[0].y, &tubiao[3], SRCINVERT);
	}
	//画出危险图标
	if (shell.live == 1&&shell.shot==0)
	{
		putimage(minePlan.x, 0, &tubiao[6], NOTSRCERASE);
		putimage(minePlan.x, 0, &tubiao[7], SRCINVERT);
		time[5] += 20;
		if (time[5] >= 2000)//控制危险图标持续的时间
		{
			time[5] = 0;
			shell.shot = 1;
			shell.x = minePlan.x;
		}
	}
	//画出炸弹
	if (shell.shot == 1)//判断导弹是否发射
	{
		putimage(shell.x, shell.y, &bomb[1],NOTSRCERASE);
		putimage(shell.x, shell.y, &bomb[0], SRCINVERT);
	}
	//打印护盾
	if (condition == 1)
	{
		if (minePlan.kind == 1)
			putimage(minePlan.x-20, minePlan.y-20, &hudun, SRCPAINT);
		else if(minePlan.kind == 2)
			putimage(minePlan.x-7, minePlan.y, &hudun, SRCPAINT);
		time[6] += 20;
		if (time[6] > 5000)
		{
			condition = 0;
			time[6] = 0;
		}
	}
}
int keyDown(IMAGE* map1,int speed)//操作按键判断
{
	//a = GetKeyState(VK_UP);//该函数通过获取虚键来判断键盘是否按下
	srand(GetTickCount());//随机数种子
	if (GetKeyState(VK_UP)< 0&&minePlan.y>0)//minePlan.y>0,限制飞机的移动范围
	{
		minePlan.y -= speed;
	}
	else if (GetKeyState(VK_LEFT)<0&&minePlan.x>-15)
	{
		minePlan.x -= speed;
	}
	else if (GetKeyState(VK_RIGHT) < 0&&minePlan.x <WIDTH-36)
	{
		minePlan.x += speed;
	}
	else if (GetKeyState(VK_DOWN) < 0 && minePlan.y < HEIGHT-50)
	{
		 minePlan.y += speed;
	}
	else if(GetKeyState(VK_ESCAPE) < 0)
	{
		return 1;
	}
	else if (GetKeyState(VK_SPACE) < 0)
	{
		return 2;
	}
	else if (GetKeyState('H') < 0&& show == 1)//按下H键释放技能
	{
		show = 0;//表示技能使用了,技能图标不再显示
		time[0] = 0;
	}
	if ((t4 - t3) > (rand() % 500 + 800))//控制敌机产生的时间 间隔
	{
		createEnemy();
		t3 = t4;
	}
	t4 = GetTickCount();
	enemyMove(3);//敌机的产生和移动,同样每次只产生一个通过循环使用移动函数,实现移动
	if (t2-t1>200)//后面为判定多久时间发射一枚子弹获取当前系统的运行时间GetKeyState(VK_CONTROL) < 0
	{
		t1 = t2;   
		createbullet();//当按下攻击键时,给子弹填充一个,下面的bulletMove()函数才会有效果
		//播放子弹发射的音效,播放之后需要关掉,才能重新播放
		//mciSendString("close gun", 0, 0, 0);
		//mciSendString("open ./Beam.wav alias gun", 0, 0, 0);
		//mciSendString("play gun", 0, 0, 0);
		//time[3] += 20;
		if ( time[0] >= 5000 || time[0] == -1)
		{
			PlaySound(TEXT("Beam.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
		}
		else//当释放技能时不播放子弹的声音
		{
			PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC | SND_PURGE);
			PlaySound(TEXT("baozou.wav"), NULL, SND_FILENAME | SND_ASYNC);
			//PlaySound(TEXT("laser shot.mp3"), NULL, SND_FILENAME | SND_ASYNC);
			CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tttt, NULL, NULL, 0);//调用线程,被其他什么东西占用了,暂停时可以播放完整的
		}
	}
	t2 = GetTickCount();
	bulletMove(10); //发射子弹 //重复执行该函数
	if (deadth() == 0)
		return 3;
	return 0;
}

这个小游戏代码超过1300行,分为了3个文件。其中AirGame.cpp文件中将多种功能合并在一个函数之中,读者可根据需求将各种功能分成多个函数,而不是小编这样合并在一起。代码的注释已经足够详细。读者可以借鉴一下,根据自己的思考将部分功能以自己的逻辑实现。
  新手学习中…

猜你喜欢

转载自blog.csdn.net/qq_45794542/article/details/106979678
今日推荐