C语言实现坦克大战

C语言实现坦克大战

期末设计和两个同学用C语言合作做了个坦克大战,就是模仿着fc上的坦克大战做的
注:虽说是用C语言实现的,但其中用到了C++中的一些东西,比如多线程,vector容器,当遇到时我会提供相应知识点的链接供大家了解;因为代码中有较详细的注释,所以只做个人认为比较重要的注释如果各位有疑问可以评论交流,我看到尽量及时回复

效果图

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

需要工具

1.项目是在vs2019上做出来的,所以推荐大家也使用vs2019进行操作,直接在官网下社区版就行,免费好用,贴个官网地址:https://visualstudio.microsoft.com/zh-hans/
2.easyx库,针对C/C++的图形库,里面有封装好的各种绘图函数,上手比较简单,适合新手使用。
下载地址:
链接:https://pan.baidu.com/s/1EycRtZ8i7EeXYDfnWjjt6w
提取码:qji3
下载完之后打开程序选择对应的vs版本安装就行了,在线文档推荐也安装,会在桌面放一个文档,方便你看相关代码,里面还有示例,建议对easyx有一定了解后在来看本篇文章。

项目打包

为了方便大家观看,这里提供本项目的压缩包,解压后在vs2019中打开即可注意内部的文件不要随意更改位置。开场背景音乐是黑道圣徒3的背景音乐,如果喜欢也推荐玩一下游戏,
链接:https://pan.baidu.com/s/1dxZH2uRWTdkcrx4RxWG1Ig
提取码:b4md
里面的打包程序压缩包里是我用vs2019的打包程序打包好的程序,解压后打开exe文件即可安装对打包感兴趣的可以看VS 2019简单快速的打包可安装项目(图文教程)

整体结构

本项目用了多个文件分别存储代码,其中包括了用于声明的头文件,以及分别用于游戏开始、1p模式、2p模式、自定义模式的cpp文件。

代码展示

头文件 game.h

#pragma once
#include<graphics.h>
#include<cstdlib>
#include<stdio.h>
#include<thread>			//用于实现多线程需要的头文件
#include<math.h>
#include<ctime>
#include<vector>			//使用vector容器需包含的头文件
#include<mmsystem.h>					//播放声音需包含的
#pragma comment(lib,"winmm.lib")		//头文件及库
using namespace std;
typedef struct direction {
	int a = 0;
	int b = 0;
	int c = 0;
	int d = 0;
}direction;

typedef struct tank{

	IMAGE img[4];								//坦克原图
	IMAGE mask[4];								//坦克掩图
	int x;										//坦克x坐标
	int y;										//坦克y坐标
	int dir = 1;								//0 上 1 下 2 左 3 右
	int vx = 6;									//坦克移动速度
	int life = 1;								//坦克生命
	int width;									//坦克当前朝向的宽度
	int height;									//坦克当前朝向的高度
	int type;									//坦克类型,拓展敌方种类用
	int stop = 0;								//对敌方坦克进行设定,AI用
	bool if_bullet = 1;							//判断判断此坦克是否还有子弹
	int  enemy_tank = 1;						//记是否是敌方的坦克1为敌方,0为1P,2为2P
	struct direction direct;					//AI用

}Tank;

typedef struct bullet{
	int x;									//子弹x坐标
	int y;									//子弹y坐标
	int vy = 15;							//子弹速度
	int dir;								//子弹方向
	tank* host;								//该子弹所属坦克,用于删除该子弹后恢复坦克if_bullet属性
	int bullet_attribute = 0;				//记子弹不同的属性(如穿甲,穿墙等),默认初值为0(普通子弹)
	int  enemy_tank;						//子弹属性,1为敌方,0为1p,2为2p
	bool if_delete = 0;						//判断该子弹是否需要被删除
}Bullet;

typedef struct boom {						//用于播放爆炸动画
	int x;					
	int y;									//爆炸发生坐标
	int type = 0;							//爆炸类型,0代表子弹爆炸,1代表坦克爆炸
	int seq = 0;							//当前播放的爆炸图片帧序
}Boom;

//通用函数
void load_play_audio(const char s[],int type,int volume);	//s字符串代表文件名,type代表操作类型,volume音量
//开始界面相关函数
void shoot(int pw, int ph);
int gamestart();
int  choosegame(int ori);
void blink(RECT r,TCHAR s[]);
//自定义界面相关函数
bool constructionmode();
void handlekey(int *pw, int *ph,int w,int h);
void setBuilding(int type, int x, int y,int w,int h);
void drawmap(int map[36][24]);
void savemap();
void initmap_construction();
void puttank(int x, int y);

//1P、2P模式相关函数
void _1pmode(bool *if_construction);
void _2pmode(bool* if_construction);
void bonus();										//生成随机奖励效果
void putplayertank(tank* tank);						//在特定位置绘制坦克
void handlekeys(tank* _1p, int player);				//处理用户键盘响应
bool checkhit(tank* tank, int enmid);				//检测坦克碰撞,enmid指坦克所处敌人链表位置,-1代表用户
bool checkturn_bug(int x, int y,int width,int height,int id);
void checkgrass();									//检测坦克是否进入草地
void drawgrass(int x, int y, int type);				//用草地覆盖坦克实现遮掩效果,type表示覆盖方式
void loadimagetank(tank* tank, const char s[]);		//加载对应坦克图像
void load_map(int level);							//根据关卡数加载地图
void drawbullet();									//绘制子弹
void shoot(tank* tank);								//根据当前坦克朝向射出子弹
void checkbullet();									//检查子弹碰撞
void boom_draw();									//绘制爆炸动画
void boom_update();									//更新爆炸帧
bool create_enm();									//生成敌人
int gameend( int mode);								//判断游戏结束条件
void gameend_play(int type, IMAGE bk);				//播放结束动画
void put_enmtank();									//绘制所有敌方坦克
void AI_attack(int x, int y, int i, int tank_x, int tank_y, int tank_dir);		//攻击组坦克AI
void enemy_move(tank* tank, int i);					//坦克移动
void AI_terminator(int x, int y, int dir,int i);		//攻击目标组AI函数			
void if_boundary(int i, int dir, int a);				//检测敌方坦克是否碰到边界,并做出相应相应
void search_path(tank* tank, int i);					//寻路函数

//声明全局变量
extern int width, height;
extern const int row, column ;
extern int map[36][24];									//地图数组,用于加载建筑及背景
extern int total_enm;									//场下地方坦克数
extern int enm;											//场上现存敌方坦克数
extern int max_enm;										//场上最大存在地方坦克数
extern int time0, timetrigger;							//用于确定绘制画面间隔
extern vector<Bullet> bullet_list;
extern vector<Tank> tank_enemy;
extern vector<Boom> boom_list;
extern tank _1p,_2p;									//1P,2P坦克结构体
extern int bonus_item;									//代表奖励类型
extern int counttime;									//奖励持续时间

//计分用变量
extern int onetank1killNum;
extern int twotank1killNum;
extern int onetankscore;
extern int twotankscore;
extern int pattern;

void PrintScore(int onetankHP, int twotankHP);
void SaveScore(int onetankscore, int twotankscore, int pattern);


这里只说第一个graphic.h,其实就是easyx,把这个头文件包含进来就能使用其中的函数了。其他的后面遇到时会再进行说明。

游戏开始界面 gamestart.cpp

#include"game.h"
using namespace std;
int width = 1280, height = 864;
int gamestart() {
	
	load_play_audio("saints.mp3", 1, 500);
	for (int i = 0; i < 255; i++)				//开场渐变
	{
		setfillcolor(RGB(i, i, i));
		solidrectangle(0, 0, width, height);
		Sleep(40);									//用于使系统停顿以实现类似按帧刷新的效果。
	}
	
	setfillcolor(BLACK);
	solidrectangle(0, 0, width, height);
	settextcolor(RED);
	settextstyle(192, 160, _T("Fixedsys 常规"));
	RECT a = { 0,60,width,384 };
	drawtext(_T("BATTLE"), &a, DT_CENTER);		
	a.top = 252,a.bottom = 516;								//画出游戏名
	drawtext(_T("CITY"), &a, DT_CENTER);
	int ori = a.bottom - 50;								
	int part = 70;
	RECT r[3] = {
		{0,ori,width,ori + part},
		{0,ori + part + 30,width,ori + 2 * part + 30},
		{0,ori + part * 2 + 60,width,ori + 3 * part + 60}
	};
	settextcolor(WHITE);
	settextstyle(70, 0, _T("Fixedsys 常规"));
	TCHAR s[3][20] = { _T("1 Player"),_T("2 Player"),_T("Construction") };
	drawtext(s[0], &r[0], DT_CENTER);
	drawtext(s[1], &r[1], DT_CENTER);
	drawtext(s[2], &r[2], DT_CENTER);			//展示可选模式
	int mode = choosegame(ori);
	blink(r[mode],s[mode]);						//闪烁特效
	load_play_audio("saints.mp3", 2, 1000);
	return mode;
}
void blink(RECT r, TCHAR s[])			//子弹击中选项后选项闪烁		
{
	for (int i = 0; i < 5; i++)
	{
		clearrectangle(r.left, r.top, r.right, r.bottom);
		Sleep(100);
		drawtext(s, &r, DT_CENTER);
		Sleep(100);
	}
}
int choosegame(int ori)
{
	IMAGE point;
	loadimage(&point, _T("Res/tank0.jpg"));
	int ph[3] = { ori + 3,ori + 3 + 100,ori + 3 + 200 };	//坦克位置
	int pw[3] = { 300,280,230 };
	int i = 0;
	setfillcolor(BLACK);
	putimage(pw[0], ph[0], &point);
	while (1)												//响应坦克操作
	{
		
		if (GetAsyncKeyState('W') < 0)	
		{
			Sleep(200);
			solidrectangle(pw[i], ph[i], pw[i] + 102, ph[i] + 64);
			if (i == 0)
				i = 2;
			else
				i--;
		}
		else if (GetAsyncKeyState('S') < 0)
		{
			Sleep(200);
			solidrectangle(pw[i], ph[i], pw[i] + 102, ph[i] + 64);
			if (i == 2)
				i = 0;
			else
				i++;
			
		}
		else if (GetAsyncKeyState(' ') < 0)					//空格键射击
		{
			shoot(pw[i]+112, ph[i]+32);
			break;
		}
		putimage(pw[i], ph[i], &point);
	}
	return i;
}
void shoot(int pw, int ph)			//射击发出子弹(仅开始界面用)
{
	
	mciSendString("play fire", NULL, 0, NULL);
	for (int i = pw; i < pw + 90; i+=3)
	{
		setfillcolor(RGB(rand() % 255, rand() % 255, rand() % 255));
		solidcircle(i, ph, 10);
		Sleep(60);
		setfillcolor(BLACK);
		solidcircle(i, ph, 10);
	}
	IMAGE img[2];
	loadimage(&img[0],_T( "Res/boom0.jpg"));
	loadimage(&img[1], _T("Res/boom1.jpg"));
	for (int i = 0; i < 2; i++)
	{
		putimage(pw + 40, ph - 32, &img[i], SRCPAINT);
		Sleep(300);
	}

}
void load_play_audio(const char s[],int type,int volume)	//type = 0代表放一次(等待播放完毕),1代表重复播放,2代表关闭音乐
{
	char a[5][50];
	sprintf_s(a[0], "open Res/audio/%s alias %s", s,s);
	sprintf_s(a[1], "setaudio %s volume to %d", s,volume);
	sprintf_s(a[2], "play %s repeat", s);
	sprintf_s(a[3], "close %s", s);
	sprintf_s(a[4], "play %s wait", s);
	mciSendString(a[0], NULL, 0, NULL);
	mciSendString(a[1], NULL, 0, NULL);
	if (type == 1)
		mciSendString(a[2], NULL, 0, NULL);
	else if(type == 0)
	{
		mciSendString(a[4], NULL, 0, NULL);
		mciSendString(a[3], NULL, 0, NULL);
	}
	else if(type == 2)
	{
		mciSendString(a[3], NULL, 0, NULL);
	}
}
int main() {
	int mode;
	bool cst = false;
	initgraph(1280, 864);
	while (1)
	{
		mode = gamestart();
		clearrectangle(0, 0, width, height);
	switch (mode)
		{
		case 0:_1pmode(&cst); break;
		case 1:_2pmode(&cst); break;
		case 2:cst = constructionmode(); break;
		}
	}

	cleardevice();
	closegraph();
	return 0;
}

这里主要说一下load_play_audio函数,里面包括了播放音效的基础操作,具体可看另一位的贴子c/c++播放音乐(PlaySound、mciSendString、mciSendCommand)以及格式化字符串:sprinf sprintf_s 的用法
还有关于键盘的响应函数如

GetAsyncKeyState('w' < 0);
GetAsyncKeyState(VK_W < 0);

判断w键按下,其中VK_W是w键的键值

自定义模式实现 constructionmode.cpp

#include"game.h"
using namespace std;
const int row = 36, column = 24;
static int map[36][24] = { 0 };
bool constructionmode()									//自定义模式主函数
{
	initmap_construction();
	int pw = 0, ph = 0;						//坦克坐标
	int w = 40, h = 24;						//坦克在宽度和高度上移动的单位
	int orx = 0, ory = 0;					//记录按下'j'或’k'键前坦克坐标
	setlinecolor(RED);
	line(960, 0, 960, 864);
	int i = 0;								//代表生成建筑的样式如4砖块4铁块
	int time = 0, timetrigger = 0;
	while (1)
	{
		time = GetTickCount();
		if (time > timetrigger)
		{
			timetrigger = time + 200;
			drawmap(map);
			handlekey(&pw, &ph, w, h);
			if (GetAsyncKeyState('J') < 0)			//放置建筑
			{
				if (orx != pw || ory != ph)
					orx = pw, ory = ph, i--;
				if (i == 13)
					i = 0;
				else
					i++;
				setBuilding(i, pw, ph, w, h);
				drawmap(map);
			}
			else if (GetAsyncKeyState('K') < 0)
			{
				if (orx != pw || ory != ph)
					orx = pw, ory = ph, i++;
				if (i == 0)
					i = 13;
				else
					i--;
				setBuilding(i, pw, ph, w, h);
				drawmap(map);
			}
			else if (GetAsyncKeyState(' ') < 0)
			{
				break;
			}
		}
	}
	savemap();
	return true;
}
void initmap_construction()			//自定义地图初始化
{			
	for (int i = 32; i < 34; i++)
		for (int j = 9; j < 15; j++)
			map[i][j] = 1;
	map[34][10] = map[35][10] = map[34][9] = map[35][9] = map[34][13] = map[35][13] = map[34][14] = map[35][14] = 1;
	map[34][11] = 6;
	map[34][12] = map[35][11] = map[35][12] = 8;
}
void setBuilding(int type, int x, int y, int w, int h)				//修改数组以摆放建筑
{
	int i = y / 24;
	int j = x / 40;
	int x0 = i * 24 + j, x1 = i * 24 + j + 1, x2 = (i + 1) * 24 + j, x3 = (i + 1) * 24 + j + 1;
	switch (type)
	{
	case 0:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 0; break;
	case 1:map[i][j] = map[i][j+1] = 1; map[i+1][j] = map[i+1][j+1] = 0; break;
	case 2:map[i][j+1] = map[i+1][j+1] = 1; map[i][j] = map[i+1][j] = 0; break;
	case 3:map[i+1][j] = map[i+1][j+1] = 1; map[i][j] = map[i][j+1] = 0; break;
	case 4:map[i][j] = map[i+1][j] = 1; map[i][j+1] = map[i+1][j+1] = 0; break;
	case 5:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 1; break;
	case 6:map[i][j] = map[i][j+1] = 4; map[i+1][j] = map[i+1][j+1] = 0; break;
	case 7:map[i][j+1] = map[i+1][j+1] = 4; map[i][j] = map[i+1][j] = 0; break;
	case 8:map[i+1][j] = map[i+1][j+1] = 4; map[i][j] = map[i][j+1] = 0; break;
	case 9:map[i][j] = map[i+1][j] = 4; map[i][j+1] = map[i+1][j+1] = 0; break;
	case 10:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 4; break;
	case 11:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 2; break;
	case 12:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 3; break;
	case 13:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 5; break;
	}
}
void drawmap(int map[36][24])			//地图绘制
{
	IMAGE img[9];			//  0:底色 , 1:砖块 , 2:草地 , 3:冰 , 4:铁 , 5:河流 , 6:指挥部 7:炸掉的指挥部
	loadimage(&img[0], _T("Res/bk.png"), 40, 24, 1);
	loadimage(&img[1], _T("Res/brick.jpg"), 40, 24, 1);
	loadimage(&img[2], _T("Res/grass.jpg"), 40, 24, 1);
	loadimage(&img[3], _T("Res/ice.jpg"), 40, 24, 1);
	loadimage(&img[4], _T("Res/iron.jpg"), 40, 24, 1);
	loadimage(&img[5], _T("Res/river.jpg"), 40, 24, 1);
	loadimage(&img[6], _T("Res/headquarter/01.jpg"),80,48,1);
	loadimage(&img[7], _T("Res/headquarter/02.jpg"), 80, 48, 1);
	for (int i = 0; i < 36; i++) {
		for (int j = 0; j < 24; j++) {
			putimage(40 * j, 24 * i, &img[map[i][j]]);
		}
	}
}
void handlekey(int* pw, int* ph, int w, int h)			//坦克移动
{
	IMAGE tank;
	int time;
	int timetrigger = 0;
	loadimage(&tank, _T("Res/1p/tank0.jpg"));
	setfillcolor(BLACK);
		
			if (GetAsyncKeyState('W') < 0)
			{

				if (*ph != 0)
					*(ph) -= 2 * h;

			}
			else if (GetAsyncKeyState('S') < 0)
			{

				if (*ph != 816)
					*(ph) += 2 * h;
			}
			else if (GetAsyncKeyState('A') < 0)
			{

				if (*pw != 0)
					*(pw) -= 2 * w;
			}
			else if (GetAsyncKeyState('D') < 0)
			{

				if (*pw != 880)
					*(pw) += 2 * w;

			}
			puttank(*pw, *ph);

}	
void puttank(int x, int y)			//坦克背景透明化
{
	IMAGE tank, mask;
	loadimage(&tank, _T("Res/construction_tank/tank0.jpg"));
	loadimage(&mask, _T("Res/construction_tank/mask.jpg"));
	putimage(x, y, &mask, SRCAND);
	putimage(x, y, &tank, SRCPAINT);
}		
void savemap()			//将地图以二维数组形式存入txt文件中
{
	map[34][11] = 6;
	map[34][12] = map[35][11] = map[35][12] = 8;
	for (int i = 0; i < 24; i++)
		map[0][i] = map[1][i] = 0;
	FILE* fp;
	fopen_s(&fp, "Res/level 0.txt", "w");
	for (int i = 0; i < 36; i++)
	{
		for (int j = 0; j < 24; j++)
			fprintf(fp, "%d ", map[i][j]);
		fprintf(fp, "\n");
	}
	fclose(fp);
}

这里涉及到的主要是文件的操作具体可看C语言文件读写函数详解
同时要说的是游戏地图我们按单位分成了36行24列,便于放置砖块等地形。

###1P模式 _1pmode.cpp

#include"game.h"

#pragma warning(disable:4996)
using namespace std;
#define tank1score 1000;//各敌方坦克分值
int map[36][24];									//地图数组,用于加载建筑及背景
int total_enm = 30;									//场下地方坦克数
int enm = 0;										//场上现存敌方坦克数
int max_enm = 4;								//场上最大存在地方坦克数
int time0 = 0, timetrigger = 0;					//用于确定绘制画面间隔
int bonus_item = 3;
int counttime = 0;
vector<Bullet> bullet_list;
vector<Tank> tank_enemy;
vector<Boom> boom_list;
tank _1p,_2p;

int onetank1killNum = 0;
int twotank1killNum = 0;
int onetankscore = 0;
int twotankscore = 0;
int pattern = 1;
void _1pmode(bool *if_construction)					//1p模式主函数
{
	int level = 1;
	int if_win = 0;									//
	load_play_audio("bk.mp3", 1, 1000);
	IMAGE bk;										//保存游戏结束时的界面用于播放后续动画
	_1p.x = 280, _1p.y = 816, _1p.vx = 5, _1p.dir = 0, _1p.life = 5, _1p.enemy_tank = 0;//设定1p各项属性
	loadimagetank(&_1p, "1p");
	tank_enemy.push_back(_1p);
	if (*if_construction)
		load_map(0), * if_construction = false;
	else
		load_map(level);
	int frame = 0;							//记录游戏周期数
	while (1)								//每循环一次代表一个游戏周期
	{
		time0 = GetTickCount();
		if (time0 > timetrigger)
		{
			frame++;
			
			timetrigger = time0 + 40;
			if_win = gameend(0);
			if (if_win == 0)
			{
				BeginBatchDraw();
				bonus();
				while (total_enm > 0 && enm < max_enm)
				{
					if (create_enm())
					{
						total_enm--;
						enm++;
					}
					else
						break;
				}
				if (counttime == 0)
				{
					for (int i = 1; i + tank_enemy.begin() != tank_enemy.end(); i++)
					{
						enemy_move(&tank_enemy[i], i);											//这里还要加转向修改
					}
				}
				else
					counttime--;
				if (counttime == 0)
				{
					if (frame % 15 == 0)
				{
					Tank mid;
					mid = tank_enemy[0];
					for (int i = 1; i + tank_enemy.begin() != tank_enemy.end(); i++) {
						
						if (!(rand() % 2) && !tank_enemy[i].type && !tank_enemy[i].stop) {
							AI_attack(tank_enemy[i].x, tank_enemy[i].y, i, mid.x, mid.y, mid.dir);
							tank_enemy[i].direct.a = 0;
							tank_enemy[i].direct.b = 0;
							tank_enemy[i].direct.c = 0;
							tank_enemy[i].direct.d = 0;
						}
						else if (tank_enemy[i].type == 1 && !tank_enemy[i].stop) {
							AI_terminator(tank_enemy[i].x, tank_enemy[i].y, tank_enemy[i].dir,i);
							tank_enemy[i].direct.a = 0;
							tank_enemy[i].direct.b = 0;
							tank_enemy[i].direct.c = 0;
							tank_enemy[i].direct.d = 0;
						}
					}

				}
				}
				
				
				drawmap(map);
				PrintScore(tank_enemy[0].life, 0);
				put_enmtank();
				putplayertank(&tank_enemy[0]);
				handlekeys(&tank_enemy[0],0);
				checkgrass();
				checkbullet();
				drawbullet();
				boom_draw();
				if (frame % 2 == 0)
					boom_update();
				
				if (frame == 50)
				{
					frame = 0;
				}
				EndBatchDraw();

			}
			else
			{
				load_play_audio("bk.mp3", 2, 1000);
				drawmap(map);
				put_enmtank();
				putplayertank(&tank_enemy[0]);
				getimage(&bk, 0, 0, 960, 864);
				gameend_play(if_win,bk);
				SaveScore(onetankscore, twotankscore, 1);
				Sleep(200);
				while (1)
				{
					if (GetAsyncKeyState(' ') < 0)
						break;
				}
				break;
			}
			
		}
		
	}
	
}
void PrintScore(int onetankHP, int twotankHP)//游戏进行时游戏界面旁的记分板,当某一玩家击杀敌方坦克或被击杀,或回合开始、回合结束及游戏结束时,刷新记分板
{
	int a4 = width - 270; int b4 = height - 150; int c4 = width - 90; int d4 = height - 50;
	int a3 = width - 270; int b3 = height - 280; int c3 = width - 90; int d3 = height - 180;
	int a2 = width - 270; int b2 = 180; int c2 = width - 90; int d2 = 280;
	int a1 = width - 270; int b1 = 50; int c1 = width - 90; int d1 = 150;
	RECT R4 = { a4,b4,c4,d4 };//绘制的四个数值放在界面右侧320*height的矩形中
	RECT R3 = { a3,b3,c3,d3 };
	RECT R2 = { a2,b2,c2,d2 };
	RECT R1 = { a1,b1,c1,d1 };
	onetankscore = onetank1killNum * tank1score;
	twotankscore = twotank1killNum * tank1score;
	char a[4][10];
	sprintf_s(a[0], "1P: %d", onetankscore);
	sprintf_s(a[1], "2P: %d", twotankscore);
	sprintf_s(a[2], "1P: %d", onetankHP);
	sprintf_s(a[3], "2P: %d", twotankHP);
	clearrectangle(960, 0, 1280, 864);//刷新记分板
	settextcolor(WHITE);//绘制记分板
	settextstyle(0, 0, _T("Fixedsys 常规"));
	drawtext(a[0], &R4, DT_CENTER);
	drawtext(a[1], &R3, DT_CENTER);
	drawtext(a[2], &R2, DT_CENTER);
	drawtext(a[3], &R1, DT_CENTER);

}
void SaveScore(int onetankscore, int twotankscore, int pattern)//游戏结束后显示结算界面,结算分数将显示历史最高的十名,另外将分数保存在文本文件中
{
	int a1 = 250;
	int a2 = 270;
	RECT R1 = { 540,50,740,150 };
	RECT R2 = { 440,180,540,200 };
	RECT R3 = { 740,180,840,200 };
	RECT R4 = { 360,a1,620,a2 };
	RECT R5 = { 660,a1,920,a2 };
	FILE* cScore;
	int nScore[10] = { 0 };
	int tail = 0;
	int i = 0;
	int j = 1;
	int i1 = 0;
	int i2 = 1;
	int j1 = 2;
	int j2 = 3;
	int nN = 0;
	if (pattern == 1)//从文件中读取至多10个分数
	{

		cScore = fopen("Res/p1score.txt", "r");
	}
	else
	{

		cScore = fopen("Res/p2score.txt", "r");
	}
	do
	{
		fscanf(cScore, "%d", &nScore[tail]);
		tail++;
	} while (!feof(cScore) && tail < 9);
	fclose(cScore);
	if (pattern == 1)//将这些分数由小到大排序
	{
		while (j <= tail)
		{
			i = 0;
			while (i < j)
			{
				if (nScore[i] > nScore[j])
				{
					nN = nScore[j];
					nScore[j] = nScore[i];
					nScore[i] = nN;
				}
				i++;
			}
			j++;
		}
	}
	else
	{
		while (j2 <= tail)
		{
			i1 = 0;
			i2 = 0;
			while (i2 < j1)
			{
				if ((nScore[i1] + nScore[i2]) > (nScore[j1] + nScore[j2]))
				{
					nN = nScore[j1];
					nScore[j1] = nScore[i1];
					nScore[i1] = nN;
					nN = nScore[j2];
					nScore[j2] = nScore[i2];
					nScore[i2] = nN;
				}
				i1 = i1 + 2;
				i2 = i2 + 2;
			}
			j1 = j1 + 2;
			j2 = j2 + 2;
		}
	}
	clearrectangle(0, 0, 1280, 864);//显示历史分数与当前分数,p1模式有十组历史分数,p2模式有五组历史分数
	settextcolor(WHITE);
	settextstyle(0, 0, _T("Fixedsys 常规"));
	char _1pscore[10], _2pscore[10];
	sprintf_s(_1pscore, "1p: %d", onetankscore);
	sprintf_s(_2pscore, "2p: %d", twotankscore);
	char score[10][20];
	j = tail + 1;
	for (i = 0; i <= tail; i++, j--)
		sprintf_s(score[i], "	%d", nScore[i]);
	drawtext(_1pscore, &R2, DT_CENTER);
	drawtext(_2pscore, &R3, DT_CENTER);
	i = tail;
	if (pattern == 1)
	{
		while (i >= 1)
		{
			drawtext(score[i], &R4, DT_CENTER);
			i = i--;
			a1 = a1 + 40;
			a2 = a2 + 40;
			R4 = { 360,a1,620,a2 };
		}
	}
	else
	{
		while (i >= 2)
		{
			drawtext(score[i], &R4, DT_CENTER);
			i = i--;
			drawtext(score[i], &R5, DT_CENTER);
			i = i--;
			a1 = a1 + 80;
			a2 = a2 + 80;
			R4 = { 360,a1,620,a2 };
			R5 = { 660,a1,920,a2 };
		}
	}

	if (pattern == 1)//从文件中读取至多10个分数
	{

		cScore = fopen("Res/p1score.txt", "w");
	}
	else
	{

		cScore = fopen("Res/p2score.txt", "w");
	}
	if (pattern == 1)//保存分数
	{
		if (onetankscore >= nScore[tail])
		{
			nScore[tail] = onetankscore;
		}
		else
		{
			if (tail < 9)
			{
				nScore[(tail + 1)] = onetankscore;
				tail++;
			}
			else
			{
				nScore[1] = onetankscore;
			}
		}
		while (tail > 1)
		{
			fprintf(cScore, "%d\n", nScore[tail]);
			tail--;
		}
	}
	else
	{
		if ((onetankscore + twotankscore) >= (nScore[tail] + nScore[(tail - 1)]))
		{
			nScore[tail] = onetankscore;
			nScore[(tail - 1)] = twotankscore;
		}
		else
		{
			nScore[1] = onetankscore;
			nScore[0] = twotankscore;
		}
		while (tail > 1)
		{
			fprintf(cScore, "%d\n", nScore[tail]);
			tail--;
		}
	}
	fclose(cScore);
}
void bonus()
{
	if (bonus_item == 3 && total_enm + enm == 25)
		bonus_item--, counttime = 500;
}
int gameend(int mode)						//返回游戏结束方式0为未结束,1为失败,2为胜利
{
	int player_left = 0;
	for (int i = 0; i + tank_enemy.begin() != tank_enemy.end(); ++i)
	{
		if (tank_enemy[i].enemy_tank != 1)
			player_left++;
	}
	if (map[34][11] == 7 || !player_left)
		return 1;
	if (total_enm == 0 && enm == 0)
		return 2;
	return 0;
}
void gameend_play(int type,IMAGE bk)
{
	
	settextstyle(100, 80, ("Fixedsys 常规"));
	setbkmode(TRANSPARENT);
	settextcolor(RED);
	char s[3][20] = { "Game","Over","Win"};
	RECT r1 = { 0,864,960,964 };
	RECT r2 = { 0,964,960,1064 };
	RECT r3 = { 0,332,960,532 };
	if (type == 1)
	{
		thread t0(load_play_audio,"gameover.mp3", 0,1000);
		t0.detach();
		while (1)
		{
			time0 = GetTickCount();
			if (time0 > timetrigger)
			{
				timetrigger = time0 + 40;
				putimage(0, 0, &bk);
				drawtext(s[0], &r1, DT_CENTER);
				drawtext(s[1], &r2, DT_CENTER);
				if (r1.top <= 334)
				{
					settextcolor(RGB(rand() % 255, rand() % 255, rand() % 255));
				}
				else
				{
					r1.bottom -= 10;
					r1.top -= 10;
					r2.bottom -= 10;
					r2.top -= 10;
				}
				if (GetAsyncKeyState(' ') < 0)
					break;
			}
		}
	}
	else if(type == 2)
	{
		thread t0(load_play_audio, "win.mp3", 0, 1000);
		t0.detach();
		while (1)
		{
			time0 = GetTickCount();
			if (time0 > timetrigger)
			{
				timetrigger = time0 + 40;
				putimage(0, 0, &bk);
				drawtext(s[2], &r3, DT_CENTER);
				if (r3.top <= 334)
				{
					settextcolor(RGB(rand() % 255, rand() % 255, rand() % 255));
				}
				else
				{
					r3.bottom -= 10;
					r3.top -= 10;
				}
				if (GetAsyncKeyState(' ') < 0)
					break;
			}
		}
	}
	bullet_list.clear();
	tank_enemy.clear();
	boom_list.clear();
	enm = 0, total_enm = 20;
	onetank1killNum = 0;
	twotank1killNum = 0;
	
}
void checkbullet()						//检查子弹碰撞
{
	int x, y;					
	
	for (int i = 0; bullet_list.begin() + i != bullet_list.end(); i++)				
	{
		x = bullet_list[i].x / 40, y = bullet_list[i].y / 24;
		Boom mid;
		if (bullet_list[i].y< 0 && bullet_list[i].dir == 0)						//检测子弹
			bullet_list[i].if_delete = 1;	
		else if (bullet_list[i].y + 18 > 864 && bullet_list[i].dir == 1)		//是否与
			bullet_list[i].if_delete = 1;
		else if (bullet_list[i].x < 0 && bullet_list[i].dir == 2)				//边界相撞
			bullet_list[i].if_delete = 1;
		else if (bullet_list[i].x + 30> 960 && bullet_list[i].dir == 3)
			bullet_list[i].if_delete = 1;
		else
		{
			switch (bullet_list[i].dir)											//检测子弹是否与地图内建筑物相撞
			{
				case 0:if (map[y][x] == 1 || map[y][x] == 4)
					map[y][x] == 1?map[y][x] = 0:map[y][x] = 4,bullet_list[i].if_delete = 1;
					if (map[y][x + 1] == 1 || map[y][x + 1] == 4)
					map[y][x + 1] == 1?map[y][x + 1] = 0:map[y][x + 1] = 4,bullet_list[i].if_delete = 1;
					break;
				case 1:if (map[y + 1][x] == 1 || map[y + 1][x] == 4)
					map[y + 1][x] == 1 ? map[y + 1][x] = 0 : map[y + 1][x] = 4,bullet_list[i].if_delete = 1;
					if (map[y + 1][x + 1] == 1 || map[y + 1][x + 1] == 4)
					map[y + 1][x + 1] == 1 ? map[y + 1][x + 1] = 0 : map[y + 1][x + 1] = 4, bullet_list[i].if_delete = 1;
					if (map[y + 1][x] == 6 || map[y + 1][x] == 8)
						map[34][11] = 7, bullet_list[i].if_delete = 1;
					if (map[y + 1][x + 1] == 6 || map[y + 1][x + 1] == 8)
						map[34][11] = 7, bullet_list[i].if_delete = 1;
					break;
				case 2:
				case 3:if (map[y][x] == 1 || map[y][x] == 4)
					map[y][x] == 1 ? map[y][x] = 0 : map[y][x] = 4, bullet_list[i].if_delete = 1;
					if (map[y + 1][x] == 1 || map[y + 1][x] == 4)
					map[y + 1][x] == 1 ? map[y + 1][x] = 0 : map[y + 1][x] = 4, bullet_list[i].if_delete = 1;
					if (map[y][x] == 6 || map[y][x] == 8)
						map[34][11] = 7, bullet_list[i].if_delete = 1;
					break;
			}
		}
		for (int j = 0; j + tank_enemy.begin() != tank_enemy.end(); j++)		//检测子弹是否与敌方坦克相撞
		{
			if (bullet_list[i].x + 21 > tank_enemy[j].x && bullet_list[i].x < tank_enemy[j].x + 80
				&& bullet_list[i].y + 12 > tank_enemy[j].y && bullet_list[i].y < tank_enemy[j].y + 48 && bullet_list[i].enemy_tank !=
				tank_enemy[j].enemy_tank && (bullet_list[i].enemy_tank == 1 || tank_enemy[j].enemy_tank == 1))
			{
				bullet_list[i].if_delete = 1;
				mid.type = 1;
				mid.x = tank_enemy[j].x;
				mid.y = tank_enemy[j].y;
				boom_list.push_back(mid);
				tank_enemy[j].life--;
				if (tank_enemy[j].life == 0)
				{
					if (tank_enemy[j].enemy_tank == 1)
						enm--;
					tank_enemy.erase(tank_enemy.begin() + j);
					if (bullet_list[i].enemy_tank == 0)
						onetank1killNum++;
					else if(bullet_list[i].enemy_tank == 2)
						twotank1killNum++;
				}
				if (tank_enemy[j].enemy_tank == 0)
				{
					tank_enemy[j].x = 280, tank_enemy[j].y = 816;
					tank_enemy[j].dir = 0;
				}
					
				else if(tank_enemy[j].enemy_tank == 2)
				{
					tank_enemy[j].x = 600, tank_enemy[j].y = 816;
					tank_enemy[j].dir = 0;
				}
				break;
			}
		}
		for (int j = 0; j + bullet_list.begin() != bullet_list.end(); ++j)		//检测子弹间是否发生碰撞
		{
			if (bullet_list[i].enemy_tank != bullet_list[j].enemy_tank && (bullet_list[i].enemy_tank == 1 || bullet_list[j].enemy_tank == 1))
			{
				if (bullet_list[i].x + 21 > bullet_list[j].x && bullet_list[i].x < bullet_list[j].x + 21
					&& bullet_list[i].y + 12 > bullet_list[j].y && bullet_list[i].y < bullet_list[j].y + 12)
				{
					bullet_list[i].if_delete = 1;
					bullet_list[j].if_delete = 1;
					
				}
			}
		}
		if (bullet_list[i].if_delete)									//删除该子弹并将其归属坦克的if_bullet置1;
		{
			mid.type = 0;
			mid.x = (bullet_list.begin() + i)->x - 20;
			mid.y = (bullet_list.begin() + i)->y - 10;
			boom_list.push_back(mid);
			(bullet_list.begin() + i)->host->if_bullet = 1;
			bullet_list.erase(bullet_list.begin() + i);
			i--;
			thread t1(load_play_audio, "boom.mp3", 0, 500);
			t1.detach();
			
		}
		else											//更新该子弹坐标
		{
			switch (bullet_list[i].dir)
			{
			case 0:bullet_list[i].y -= bullet_list[i].vy; break;
			case 1:bullet_list[i].y += bullet_list[i].vy; break;
			case 2:bullet_list[i].x -= bullet_list[i].vy; break;
			case 3:bullet_list[i].x += bullet_list[i].vy; break;
			}
		}
	}
	
}
void drawbullet()					//绘制子弹
{
	IMAGE img[4];
	IMAGE mask[4];
	loadimage(&img[0], "Res/bullet/bullet0.jpg");
	loadimage(&img[1], "Res/bullet/bullet1.jpg");
	loadimage(&img[2], "Res/bullet/bullet2.jpg");
	loadimage(&img[3], "Res/bullet/bullet3.jpg");
	loadimage(&mask[0], "Res/bullet/mask0.jpg");
	loadimage(&mask[1], "Res/bullet/mask1.jpg");
	loadimage(&mask[2], "Res/bullet/mask2.jpg");
	loadimage(&mask[3], "Res/bullet/mask3.jpg");
	for (int i = 0; bullet_list.begin() + i != bullet_list.end(); i++)
	{
		putimage(bullet_list[i].x, bullet_list[i].y, &mask[bullet_list[i].dir], SRCAND);
		putimage(bullet_list[i].x, bullet_list[i].y, &img[bullet_list[i].dir], SRCPAINT);
	}
}
void boom_draw()					//绘制爆炸图片
{
	IMAGE img[5];
	IMAGE mask[5];
	char s[2][50];
	for (int i = 0; i < 5; i++)
	{
		sprintf_s(s[0], "Res/boom/boom%d.jpg", i);
		sprintf_s(s[1], "Res/boom/mask%d.jpg", i);
		loadimage(&img[i], s[0]);
		loadimage(&mask[i], s[1]);
	}
	for (int i = 0; i + boom_list.begin() != boom_list.end(); ++i)
	{
		if (boom_list[i].seq == 3)
		{
			boom_list[i].x -= 16, boom_list[i].y -= 12;
		}
		putimage(boom_list[i].x, boom_list[i].y, &mask[boom_list[i].seq], SRCAND);
		putimage(boom_list[i].x, boom_list[i].y, &img[boom_list[i].seq], SRCPAINT);
	}
}
void boom_update()						//更新爆炸帧数
{
	for (int i = 0; i + boom_list.begin() != boom_list.end(); ++i)
	{
		boom_list[i].seq++;
		if ((boom_list[i].type == 0 && boom_list[i].seq == 3) || (boom_list[i].type == 1 && boom_list[i].seq == 5))
		{
			boom_list.erase(boom_list.begin() + i);
			--i;
			continue;
		}
		
	}
}
bool checkice(tank* tank)
{
	int i = tank->y / 24;
	int j = tank->x / 40;
	switch (tank->dir)
	{
	case 0: if (map[i][j] == 3)
		return true;
		break;
	case 1:if (map[i + 1][j] == 3)
		return true;
		break;
	case 2:if (map[i][j] == 3)
		return true;
		break;
	case 3:if (map[i][j + 1] == 3)
		return true;
	}
	return false;
}
void checkgrass()				//检查该坦克是否进入草地
{
	for (int n = 0; n + tank_enemy.begin() != tank_enemy.end(); ++n)
	{
		int i = tank_enemy[n].y / 24;
		int j = tank_enemy[n].x / 40;
		switch (tank_enemy[n].dir)
		{
		case 0: if (map[i][j] == 2 && map[i][j + 1] == 2)
			drawgrass(j * 40, i * 24, 0);
			if (map[i + 1][j] == 2 && map[i + 1][j + 1] == 2)
				drawgrass(j * 40, i * 24, 1);
			if (map[i + 2][j] == 2 && map[i + 2][j + 1] == 2)
				drawgrass(j * 40, i * 24 + 24, 1);
			break;
		case 1:if (map[i + 1][j] == 2 && map[i + 1][j + 1] == 2)
			drawgrass(j * 40, i * 24, 1);
			if (map[i][j] == 2 && map[i + 1][j + 1] == 2)
				drawgrass(j * 40, i * 24, 0);
			if (map[i - 1][j] == 2 && map[i - 1][j + 1] == 2)
				drawgrass(j * 40, i * 24 - 24, 0);
			break;
		case 2:if (map[i][j] == 2 && map[i + 1][j] == 2)
			drawgrass(j * 40, i * 24, 2);
			if (map[i][j + 1] == 2 && map[i + 1][j + 1] == 2)
				drawgrass(j * 40, i * 24, 3);
			
			break;
		case 3:if (map[i][j + 1] == 2 && map[i + 1][j + 1] == 2)
			drawgrass(j * 40, i * 24, 3);
			if (map[i][j] == 2 && map[i + 1][j] == 2)
				drawgrass(j * 40, i * 24, 2);
			if (map[i][j - 1] == 2 && map[i + 1][j - 1] == 2)
				drawgrass(j * 40 - 40, i * 24, 2);
			break;


		}
	}
	
}
void handlekeys(tank* tank,int player)		//响应玩家键盘输入 player为0代表1P,为1代表2P,同时对应坦克链表中位置ID
{
	int x = (tank->x % 40 <= 20) ? tank->x / 40 * 40 : (tank->x / 40 + 1) * 40;		//
	int y = (tank->y % 24 <= 12) ? tank->y / 24 * 24 : (tank->y / 24 + 1) * 24;		//当发生转向时重置的x、y坐标
	if ((GetAsyncKeyState('W') < 0 && !player) || (GetAsyncKeyState(VK_UP) < 0 && player))
	{
		
		if (tank->x % 40 != 0 && checkturn_bug(x,tank->y,tank->width,tank->height,player))
		{
			tank->x = x;
		}
		tank->dir = 0;
		if (!checkhit(tank,player))
			tank->y -= tank->vx;

	}
	else if ((GetAsyncKeyState('S') < 0 && !player) || (GetAsyncKeyState(VK_DOWN) < 0 && player))
	{
		
		if (tank->x % 40 != 0 && checkturn_bug(x, tank->y, tank->width, tank->height, player))
		{
			tank->x = x;
		}
		tank->dir = 1;
		if (!checkhit(tank,player))
			tank->y += tank->vx;
		
	}
	else if ((GetAsyncKeyState('A') < 0 && !player) || (GetAsyncKeyState(VK_LEFT) < 0 && player))
	{
		
		if (tank->y % 24 != 0 && checkturn_bug(tank->x,y,tank->width,tank->height, player))
		{
			tank->y = y;
		}
		tank->dir = 2;
		if (!checkhit(tank,player))
			tank->x -= tank->vx;
		
	}
	else if ((GetAsyncKeyState('D') < 0 && !player) || (GetAsyncKeyState(VK_RIGHT) < 0 && player))
	{
		
		if (tank->y % 24 != 0 && checkturn_bug(tank->x, y, tank->width, tank->height, player))
		{
			tank->y = y;
		}
		tank->dir = 3;
		if (!checkhit(tank,player))
			tank->x += tank->vx;
		
	}
	if ((((GetAsyncKeyState('J') < 0 || GetAsyncKeyState('K') < 0) && !player) || 
		((GetAsyncKeyState(VK_NUMPAD4) < 0 || GetAsyncKeyState(VK_NUMPAD5) < 0) && player)) && tank->if_bullet == 1)
	{
		shoot(tank);
	}
	else if (GetAsyncKeyState('M') < 0 && !player)
	{
		Boom mid;
		for (int i = player+1; i + tank_enemy.begin() != tank_enemy.end(); ++i)
		{
			mid.type = 1;
			mid.x = tank_enemy[i].x;
			mid.y = tank_enemy[i].y;
			boom_list.push_back(mid);
			tank_enemy[i].life--;
			if (tank_enemy[i].life == 0)
			{
				if (tank_enemy[i].enemy_tank == 1)
					enm--;
				tank_enemy.erase(tank_enemy.begin() + i);
				i--;
			}
			
		}

	}
}
void shoot(tank* tank)						//根据该坦克方向射出子弹
{
	Bullet mid_bullet;
	mid_bullet.dir = tank->dir;
	mid_bullet.enemy_tank = tank->enemy_tank;
	switch (tank->dir)
	{
	case 0:mid_bullet.x = tank->x + tank->width / 2 - 11, mid_bullet.y = tank->y; break;
	case 1:mid_bullet.x = tank->x + tank->width / 2 - 11, mid_bullet.y = tank->y + tank->height - 18; break;
	case 2:mid_bullet.x = tank->x - 15, mid_bullet.y = tank->y + tank->height / 2 - 6; break;
	case 3:mid_bullet.x = tank->x + tank->width - 15, mid_bullet.y = tank->y + tank->height / 2 - 6; break;

	}
	mid_bullet.host = tank;
	bullet_list.push_back(mid_bullet);
	tank->if_bullet = 0;
	thread t1(load_play_audio,("tankfire1.mp3"),0,1000);
	t1.detach();
}
void drawgrass(int x, int y,int type)		//画出草地 type代表画草地的数量及类型0上2,1下2,2左2,3右2
{
	IMAGE grass;
	IMAGE mask;
	loadimage(&mask, "Res/grass1.jpg", 40, 24);
	loadimage(&grass, "Res/grass.jpg", 40, 24);
	switch (type)
	{
	case 0:putimage(x, y, &mask, SRCAND);
		 putimage(x, y, &grass, SRCPAINT);
		 putimage(x + 40, y, &mask, SRCAND);
		putimage(x + 40, y, &grass, SRCPAINT); break;
	case 1:putimage(x, y + 24, &mask, SRCAND);
		putimage(x, y + 24, &grass, SRCPAINT);
		putimage(x + 40, y + 24, &mask, SRCAND);
		putimage(x + 40, y + 24, &grass, SRCPAINT); break;
	case 2:putimage(x, y, &mask, SRCAND);
		putimage(x, y, &grass, SRCPAINT);
		putimage(x, y + 24, &mask, SRCAND);
		putimage(x, y + 24, &grass, SRCPAINT); break;
	case 3:putimage(x + 40, y, &mask, SRCAND);
		putimage(x + 40, y, &grass, SRCPAINT);
		putimage(x + 40, y + 24, &mask, SRCAND);
		putimage(x + 40, y + 24, &grass, SRCPAINT); break;
	case 4:putimage(x, y, &mask, SRCAND);
		putimage(x, y, &grass, SRCPAINT);
		putimage(x + 40, y, &grass, SRCPAINT);
		putimage(x, y + 24, &grass, SRCPAINT);
		putimage(x + 40, y + 24, &grass, SRCPAINT);
	}
}
bool checkhit(tank* tank,int enmid)							//检测碰撞
{
	
	int j = tank->x / 40;
	int i = tank->y / 24;
	if (i == 0 && tank->y - tank->vx < 0 && tank->dir == 0)						//检测坦克是否与边界相撞
		return true;
	else if (tank->y + tank->vx +  tank->height> 864 && tank->dir == 1)
		return true;
	if (tank->x - tank->vx < 0 && tank->dir == 2)
		return true;
	else if (tank->x + tank->vx + tank->width > 960 && tank->dir == 3)
		return true;
	switch (tank->dir)												//检测坦克是否与不可穿过建筑物相撞
	{
	case 0: if ((tank->y - tank->vx) < i * 24 && ((map[i - 1][j] == 1 || map[i - 1][j] == 4 || map[i - 1][j] == 5)
		|| (map[i - 1][j + 1] == 1  || map[i - 1][j + 1] == 4 || map[i - 1][j + 1] == 5)))
		return true; break;
	case 1: if (tank->y + tank->vx + tank->height >= (i + 2) * 24 && ((map[i + 2][j] == 1 ||
		map[i + 2][j] == 4 || map[i + 2][j] == 5) || (map[i + 2][j + 1] == 1 ||
			map[i + 2][j + 1] == 4 || map[i + 2][j + 1] == 5)))
		return true; break;
	case 2: if (tank->x - tank->vx < j * 40 && ((map[i][j - 1] == 1 || map[i][j - 1] == 4 || map[i][j - 1] == 5) 
		|| (map[i + 1][j - 1] == 1 || map[i + 1][j - 1] == 4 || map[i + 1][j - 1] == 5)))
		return true; break;
	case 3: if (tank->x + tank->vx + tank->width > (j + 2) * 40 && ((map[i][j + 2] == 1 || map[i][j + 2] == 4 
		|| map[i][j + 2] == 5) || (map[i + 1][j + 2] == 1 || map[i + 1][j + 2] == 4 || map[i + 1][j + 2] == 5)))
		return true; break;
	}
	int xn, yn;				//记录此坦克下一时刻坐标
	switch (tank->dir)
	{
	case 0: xn = tank->x, yn = tank->y - tank->vx; break;
	case 1: xn = tank->x, yn = tank->y + tank->vx; break;
	case 2: xn = tank->x - tank->vx, yn = tank->y; break;
	case 3: xn = tank->x + tank->vx, yn = tank->y; break;
	}
	for (int i = 0; i + tank_enemy.begin() != tank_enemy.end(); i++)		//检测坦克之间是否相撞
	{
		if (enmid == i)
			continue;
		if (tank->x + 80 > tank_enemy[i].x && tank->x < tank_enemy[i].x + 80
			&& tank->y + 48 > tank_enemy[i].y && tank->y < tank_enemy[i].y + 48)
			return false;
		if (xn + 80 > tank_enemy[i].x && xn < tank_enemy[i].x + 80 
			&& yn + 48 > tank_enemy[i].y && yn < tank_enemy[i].y + 48)
			return true;
	}
	return false;
}
bool checkturn_bug(int x, int y,int width,int height,int id)
{
	for (int i = 0; i + tank_enemy.begin() != tank_enemy.end(); ++i)
	{
		if (i == id)
			continue;
		if (tank_enemy[i].x + tank_enemy[i].width > x && tank_enemy[i].x < x + width&&
			tank_enemy[i].y < y + height && tank_enemy[i].y + tank_enemy[i].height > y)
			return false;
	}
		
	return true;
}
bool create_enm()							//生成敌方单位
{
	Tank mid;
	srand(GetTickCount());
	int x[4] = { 0, 160, 400, 880 };
	int able[4] = { -1,-1,-1,-1 };
	int count = 0;						//统计可使用出生点数量
	mid.y = 0;
	int i, j;
	for (i = 0; i < 4; i++)
	{
		for (j = 0; j + tank_enemy.begin() != tank_enemy.end(); j++)
		{
			if (tank_enemy[j].y < 57 && tank_enemy[j].x > x[i] - 85 && tank_enemy[j].x < x[i] + 85)
				break;
		}
		if (j + tank_enemy.begin() == tank_enemy.end())
		{
			able[count++] = i;
		}
	}
	if (able[0] == -1)
		return false;
	else
		mid.x = x[able[rand() % count]];
	
	mid.type = (rand() % 2 == 1) ? 0 : 1;

	int random = rand() % 9 ;
	
		if (random <= 2)
			loadimagetank(&mid, "tank1");
		else if (random <= 5)
			loadimagetank(&mid, "tank2");
		else
			loadimagetank(&mid, "tank3");
		tank_enemy.push_back(mid);
		return true;
}
void put_enmtank()					//遍历坦克向量放置坦克
{
	
	for (int i = 1; i + tank_enemy.begin() != tank_enemy.end(); i++)
	{
		if (tank_enemy[i].enemy_tank == 1)
		{
			putplayertank(&tank_enemy[i]);
		}
	}
}
void putplayertank(tank *tank)								//放置坦克图片
{
	
	putimage(tank->x, tank->y, &tank->mask[tank->dir], SRCAND);
	putimage(tank->x, tank->y, &tank->img[tank->dir], SRCPAINT);
}
void AI_attack(int x, int y, int i, int tank_x, int tank_y, int tank_dir) {
	int row = y / 24;
	int col = x / 40;
	int tank_row = tank_y / 24;
	int tank_col = tank_x / 40;
	int dert_x = x - tank_x;
	int dert_y = y - tank_y;
	int if_shoot = 1;
	int if_bound = 0;

	search_path(&tank_enemy[i], i);
	if (abs(dert_x) < 80 ) {
		if (dert_y > 0) {								//敌方坦克在玩家下方,(如果玩家与敌方坦克之间没有铁块阻挡,那么敌方坦克转向开炮即可;如果有铁块阻挡,则随机选择一个方向,概率分别为(由大到小):上,左,右,下;每次判断后置停8次)
			for (int i = row; i > tank_row; i--) {
				if (map[i][col] == 4 || map[i][col + 1] == 4) {
					if_shoot = 0;
				}
			}
			if (if_shoot) {
				tank_enemy[i].dir = 0;
			}
			else {
				for (;;) {
					if (!(rand() % 5) && tank_enemy[i].direct.a) {
						tank_enemy[i].dir = 0;
						break;
					}
					if (!(rand() % 10) && tank_enemy[i].direct.c) {
						tank_enemy[i].dir = 2;
						break;
					}
					if (!(rand() % 15) && tank_enemy[i].direct.d) {
						tank_enemy[i].dir = 3;
						break;
					}
					if (!(rand() % 20) && tank_enemy[i].direct.b) {
						tank_enemy[i].dir = 1;
						break;
					}
				}
			}
		}
		else {
			for (int i = row; i < tank_row; i++) {
				if (map[i][col] == 4 || map[i][col + 1] == 4) {
					if_shoot = 0;
				}
			}
			if (if_shoot) {
				tank_enemy[i].dir = 1;
			}
			else {
				for (;;) {
					if (!(rand() % 5) && tank_enemy[i].direct.b) {
						tank_enemy[i].dir = 1;
						break;
					}
					if (!(rand() % 10) && tank_enemy[i].direct.c) {
						tank_enemy[i].dir = 2;
						break;
					}
					if (!(rand() % 15) && tank_enemy[i].direct.d) {
						tank_enemy[i].dir = 3;
						break;
					}
					if (!(rand() % 20) && tank_enemy[i].direct.a) {
						tank_enemy[i].dir = 0;
						break;
					}
				}
			}
		}
		if (if_shoot && tank_enemy[i].if_bullet) {
			shoot(&tank_enemy[i]);
			tank_enemy[i].if_bullet = 0;
		}
	}
	else if (abs(dert_y) < 48 ) {
		if (dert_x > 0) {
			for (int i = col; i > tank_col; i--) {
				if (map[row][i] == 4 || map[row + 1][i] == 4) {
					if_shoot = 0;
				}
			}
			if (if_shoot) {
				tank_enemy[i].dir = 2;
			}
			else {
				for (;;) {
					if (!(rand() % 5) && tank_enemy[i].direct.c) {
						tank_enemy[i].dir = 2;
						break;
					}
					if (!(rand() % 10) && tank_enemy[i].direct.a) {
						tank_enemy[i].dir = 0;
						break;
					}
					if (!(rand() % 15) && tank_enemy[i].direct.b) {
						tank_enemy[i].dir = 1;
						break;
					}
					if (!(rand() % 20) && tank_enemy[i].direct.d) {
						tank_enemy[i].dir = 3;
						break;
					}
				}
			}
		}
		else {
			for (int i = col; i < tank_col; i++) {
				if (map[row][i] == 4 || map[row + 1][i] == 4) {
					if_shoot = 0;
				}
			}
			if (if_shoot) {
				tank_enemy[i].dir = 3;
			}
			else {
				for (;;) {
					if (!(rand() % 5) && tank_enemy[i].direct.d) {
						tank_enemy[i].dir = 3;
						break;
					}
					if (!(rand() % 10) && tank_enemy[i].direct.a) {
						tank_enemy[i].dir = 0;
						break;
					}
					if (!(rand() % 15) && tank_enemy[i].direct.b) {
						tank_enemy[i].dir = 1;
						break;
					}
					if (!(rand() % 20) && tank_enemy[i].direct.c) {
						tank_enemy[i].dir = 2;
						break;
					}
				}
			}
		}
		if (if_shoot && tank_enemy[i].if_bullet) {
			shoot(&tank_enemy[i]);
			tank_enemy[i].if_bullet = 0;
		}

	}

	
	if (checkhit(&tank_enemy[i], i)) {
		switch (tank_enemy[i].dir)
		{
		case 0: if (tank_enemy[i].y - tank_enemy[i].vx < 0) {
			for (;;) {
				if (!(rand() % 5) && tank_enemy[i].direct.b) {
					tank_enemy[i].dir = 1;
					break;
				}
				if (!(rand() % 10) && tank_enemy[i].direct.c) {
					tank_enemy[i].dir = 2;
					break;
				}
				if (!(rand() % 10) && tank_enemy[i].direct.d) {
					tank_enemy[i].dir = 3;
					break;
				}
			}
			if_bound = 1;
		}	break;
		case 1: if (tank_enemy[i].y + tank_enemy[i].vx + tank_enemy[i].height > 864) {
			for (;;) {
				if (!(rand() % 5) && tank_enemy[i].direct.a) {
					tank_enemy[i].dir = 0;
					break;
				}
				if (!(rand() % 10) && tank_enemy[i].direct.c) {
					tank_enemy[i].dir = 2;
					break;
				}
				if (!(rand() % 10) && tank_enemy[i].direct.d) {
					tank_enemy[i].dir = 3;
					break;
				}
			}
			if_bound = 1;
		}	break;
		case 2: if (tank_enemy[i].x - tank_enemy[i].vx < 0) {
			for (;;) {
				if (!(rand() % 5) && tank_enemy[i].direct.d) {
					tank_enemy[i].dir = 3;
					break;
				}
				if (!(rand() % 10) && tank_enemy[i].direct.a) {
					tank_enemy[i].dir = 0;
					break;
				}
				if (!(rand() % 10) && tank_enemy[i].direct.b) {
					tank_enemy[i].dir = 1;
					break;
				}
			}
			if_bound = 1;
		}	break;
		case 3: if (tank_enemy[i].x + tank_enemy[i].vx + tank_enemy[i].width > 960) {
			for (;;) {
				if (!(rand() % 5) && tank_enemy[i].direct.c) {
					tank_enemy[i].dir = 2;
					break;
				}
				if (!(rand() % 10) && tank_enemy[i].direct.a) {
					tank_enemy[i].dir = 0;
					break;
				}
				if (!(rand() % 10) && tank_enemy[i].direct.b) {
					tank_enemy[i].dir = 1;
					break;
				}
			}
			if_bound = 1;
		}	break;
		}
		if (!if_bound) {
			tank_enemy[i].direct.a = 0;
			tank_enemy[i].direct.b = 0;
			tank_enemy[i].direct.c = 0;
			tank_enemy[i].direct.d = 0;
			search_path(&tank_enemy[i], i);
			if (dert_x > 0) {
				for (;;) {
					if (!(rand() % 5) && tank_enemy[i].direct.c) {
						tank_enemy[i].dir = 2;
						break;
					}
					if (!(rand() % 10) && tank_enemy[i].direct.a) {
						tank_enemy[i].dir = 0;
						break;
					}
					if (!(rand() % 15) && tank_enemy[i].direct.b) {
						tank_enemy[i].dir = 1;
						break;
					}
					if (!(rand() % 20) && tank_enemy[i].direct.d) {
						tank_enemy[i].dir = 3;
						break;
					}
				}
			}
			else {
				for (;;) {
					if (!(rand() % 5) && tank_enemy[i].direct.d) {
						tank_enemy[i].dir = 3;
						break;
					}
					if (!(rand() % 10) && tank_enemy[i].direct.b) {
						tank_enemy[i].dir = 1;
						break;
					}
					if (!(rand() % 18) && tank_enemy[i].direct.a) {
						tank_enemy[i].dir = 0;
						break;
					}
					if (!(rand() % 33) && tank_enemy[i].direct.c) {
						tank_enemy[i].dir = 2;
						break;
					}
				}
			}
		}

	}
	else if (!checkhit(&tank_enemy[i], i) ) {
		if (abs(dert_x) > abs(dert_y)) {						//敌方坦克与玩家之间y轴差距更小(即优先选择追赶y),优先顺序为:
			for (;;) {
				if (!(rand() % 5) && tank_enemy[i].direct.a) {
					tank_enemy[i].dir = 0;
					break;
				}
				if (!(rand() % 8) && tank_enemy[i].direct.b) {
					tank_enemy[i].dir = 1;
					break;
				}
				if (!(rand() % 44) && tank_enemy[i].direct.c) {
					tank_enemy[i].dir = 2;
					break;
				}
				if (!(rand() % 29) && tank_enemy[i].direct.d) {
					tank_enemy[i].dir = 3;
					break;
				}
			}
		}
		else {
			for (;;) {
				if (!(rand() % 10) && tank_enemy[i].direct.c) {
					tank_enemy[i].dir = 2;
					break;
				}
				if (!(rand() % 10) && tank_enemy[i].direct.d) {
					tank_enemy[i].dir = 3;
					break;
				}
				if (!(rand() % 30) && tank_enemy[i].direct.a) {
					tank_enemy[i].dir = 0;
					break;
				}
				if (!(rand() % 30) && tank_enemy[i].direct.b) {
					tank_enemy[i].dir = 1;
					break;
				}
			}
		}
	}

}
void AI_terminator(int x, int y, int dir, int i) {
	void A_(int x, int y, int dir, int i);
	int dert_x = x - 10 * 40;
	int dert_y = y - 34 * 24;
	int asd;								//开火概率设定
	int if_bound = 0;

	search_path(&tank_enemy[i], i);

	if_boundary(i, dir, if_bound);
	if (if_bound) {
		tank_enemy[i].stop = 0;
		return;
	}

	if (checkhit(&tank_enemy[i], i)) {
		search_path(&tank_enemy[i], i);
		for (;;) {
			if ((rand() % 2) && tank_enemy[i].direct.b) {
				if (tank_enemy[i].x % 40 != 0 && checkturn_bug((tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40,
					tank_enemy[i].y, tank_enemy[i].width, tank_enemy[i].height, i))
				{
					tank_enemy[i].x = (tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40;
				}
				tank_enemy[i].dir = 1;
				break;
			}
			if ((rand() % 2) && tank_enemy[i].direct.c) {
				if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
				{
					tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
				}
				tank_enemy[i].dir = 2;
				break;
			}
			if ((rand() % 2) && tank_enemy[i].direct.d) {
				if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
				{
					tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
				}
				tank_enemy[i].dir = 3;
				break;
			}
			if (!(rand() % 10) && tank_enemy[i].direct.a) {
				if (tank_enemy[i].x % 40 != 0 && checkturn_bug((tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40,
					tank_enemy[i].y, tank_enemy[i].width, tank_enemy[i].height, i))
				{
					tank_enemy[i].x = (tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40;
				}
				tank_enemy[i].dir = 0;
				break;
			}
		}
		tank_enemy[i].stop = 0;
		return;
	}

	if (tank_enemy[i].stop) {
		tank_enemy[i].stop--;
	}

	if (dert_y < 0 && tank_enemy[i].direct.b) {
		if (tank_enemy[i].x % 40 != 0 && checkturn_bug((tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40,
			tank_enemy[i].y, tank_enemy[i].width, tank_enemy[i].height, i))
		{
			tank_enemy[i].x = (tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40;
		}
		tank_enemy[i].dir = 1;
		if (!rand() % 10) {
			tank_enemy[i].stop = 4;
		}
	}
	if (dert_x > 40 * 6 && !tank_enemy[i].stop) {
		if (tank_enemy[i].direct.c) {
			if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
			{
				tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
			}
			tank_enemy[i].dir = 2;
		}
		else {
			if (tank_enemy[i].direct.a) {
				if (tank_enemy[i].x % 40 != 0 && checkturn_bug((tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40,
					tank_enemy[i].y, tank_enemy[i].width, tank_enemy[i].height, i))
				{
					tank_enemy[i].x = (tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40;
				}
				tank_enemy[i].dir = 0;
			}
			if (tank_enemy[i].direct.d) {
				if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
				{
					tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
				}
				tank_enemy[i].dir = 3;
			}
		}
		if (!rand() % 10) {
			tank_enemy[i].stop = 4;
		}
	}
	if (dert_x > 40 * 4 && !tank_enemy[i].stop) {
		if (tank_enemy[i].direct.d) {
			if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
			{
				tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
			}
			tank_enemy[i].dir = 3;
		}
		else {
			if (tank_enemy[i].direct.a) {
				tank_enemy[i].dir = 0;
			}
			if (tank_enemy[i].direct.c) {
				if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
				{
					tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
				}
				tank_enemy[i].dir = 2;
			}
		}
		if (!rand() % 10) {
			tank_enemy[i].stop = 4;
		}
	}

	if (y <= 12 * 24) {
		asd = !(rand() % 10);
	}
	else {
		asd = !(rand() % 3);
	}
	if ((dert_x >= 0 && dert_x <= 40 && tank_enemy[i].dir == 1) || (dert_y >= 0 && dert_y <= 48)) {
		if (tank_enemy[i].if_bullet && !asd) {
			shoot(&tank_enemy[i]);
			tank_enemy[i].if_bullet = 0;
		}
	}
}
void if_boundary(int i, int dir, int a) {
	search_path(&tank_enemy[i], i);

	switch (dir)
	{
	case 0: if (tank_enemy[i].y - tank_enemy[i].vx < 0) {
		tank_enemy[i].dir = 1;
		a = 1;
	}	break;
	case 1: if (tank_enemy[i].y + tank_enemy[i].vx + tank_enemy[i].height > 864) {
		if (tank_enemy[i].x > 10 * 40) {
			tank_enemy[i].dir = 2;
		}
		else {
			tank_enemy[i].dir = 3;
		}
		if (tank_enemy[i].if_bullet) {
			shoot(&tank_enemy[i]);
			tank_enemy[i].if_bullet = 0;
		}
		a = 1;
	}	break;
	case 2: if (tank_enemy[i].x - tank_enemy[i].vx < 0) {
		for (;;) {
			if ((rand() % 2) && tank_enemy[i].direct.b) {
				tank_enemy[i].dir = 1;
				break;
			}
			if (!(rand() % 10) && tank_enemy[i].direct.d) {
				tank_enemy[i].dir = 3;
				break;
			}
			if (!(rand() % 15) && tank_enemy[i].direct.a) {
				tank_enemy[i].dir = 0;
				break;
			}
		}
		a = 1;
	}	break;
	case 3: if (tank_enemy[i].x + tank_enemy[i].vx + tank_enemy[i].width > 960) {
		for (;;) {
			if (!(rand() % 2) && tank_enemy[i].direct.b) {
				tank_enemy[i].dir = 1;
				break;
			}
			if (!(rand() % 10) && tank_enemy[i].direct.c) {
				tank_enemy[i].dir = 2;
				break;
			}
			if (!(rand() % 15) && tank_enemy[i].direct.a) {
				tank_enemy[i].dir = 0;
				break;
			}
		}
		a = 1;
	}	break;
	}
}
void search_path(tank* tank, int i) {
	int col = tank->x / 40;
	int row = tank->y / 24;
	if (map[row - 1][col] == 0 || map[row - 1][col] == 1 || map[row - 1][col] == 2 || map[row - 1][col + 1] == 0 || map[row - 1][col + 1] == 1 || map[row - 1][col + 1] == 2) {
		tank->direct.a = 1;
		if ((map[row - 1][col] == 1 || map[row - 1][col + 1] == 1) && tank->if_bullet && tank->dir == 0) {
			shoot(tank);
			tank->if_bullet = 0;
		}
	}
	if (map[row + 2][col] == 0 || map[row + 2][col] == 1 || map[row + 2][col] == 2 || map[row + 2][col + 1] == 0 || map[row + 2][col + 1] == 1 || map[row + 2][col + 1] == 2) {
		tank->direct.b = 1;
		if ((map[row + 2][col] == 1 || map[row + 2][col + 1] == 1) && tank->if_bullet && tank->dir == 1) {
			shoot(tank);
			tank->if_bullet = 0;
		}
	}
	if (map[row][col - 1] == 0 || map[row][col - 1] == 1 || map[row][col - 1] == 2 || map[row + 1][col - 1] == 0 || map[row + 1][col - 1] == 1 || map[row + 1][col - 1] == 2) {
		tank->direct.c = 1;
		if ((map[row][col - 1] == 1 || map[row + 1][col - 1] == 1) && tank->if_bullet && tank->dir == 2) {
			shoot(tank);
			tank->if_bullet = 0;
		}
	}
	if (map[row][col + 2] == 0 || map[row][col + 2] == 1 || map[row][col + 2] == 2 || map[row + 1][col + 2] == 0 || map[row + 1][col + 2] == 1 || map[row + 1][col + 2] == 2) {
		tank->direct.d = 1;
		if ((map[row][col + 2] == 1 || map[row + 1][col + 2] == 1) && tank->if_bullet && tank->dir == 3) {
			shoot(tank);
			tank->if_bullet = 0;
		}
	}

	switch (tank->dir)
	{
	case 0: if (checkhit(tank, i) && tank->direct.a) {
		tank->direct.a = 0;
	}	break;
	case 1: if (checkhit(tank, i) && tank->direct.b) {
		tank->direct.b = 0;
	}	break;
	case 2: if (checkhit(tank, i) && tank->direct.c) {
		tank->direct.c = 0;
	}	break;
	case 3: if (checkhit(tank, i) && tank->direct.d) {
		tank->direct.d = 0;
	}	break;
	}
}
void enemy_move(tank* tank, int i) {
	switch (tank->dir) {
	case 0:	if (!checkhit(tank, i)) {
		tank->y -= tank->vx;
	}		break;
	case 1: if (!checkhit(tank, i)) {
		tank->y += tank->vx;
	}	break;
	case 2: if (!checkhit(tank, i)) {
		tank->x -= tank->vx;
	}	break;
	case 3: if (!checkhit(tank, i)) {
		tank->x += tank->vx;
	}	break;
	}
}
void loadimagetank(tank* tank,const char s[])				//加载坦克图片
{
	char a[2][4][30];
	for (int i = 0; i < 4; i++)
	{
		sprintf_s(a[0][i], "Res/%s/tank%d.jpg", s,i);
		sprintf_s(a[1][i], "Res/%s/mask%d.jpg", s, i);
		loadimage(&tank->img[i], a[0][i]);
		loadimage(&tank->mask[i], a[1][i]);

	}
	tank->width = tank->img[2].getwidth();
	tank->height = tank->img[0].getheight();
}
void load_map(int level)								//从文件中读取地图存入二维数组
{
	FILE* fp;
	char s[20] = "";
	sprintf_s(s, "Res/level %d.txt",level);
	fopen_s(&fp, s, "r");
	for (int i = 0; i < 36; i++)
		for (int j = 0; j < 24; j++)
			fscanf_s(fp, "%d", &map[i][j]);
	fclose(fp);
}

因为是游戏主要的部分所以代码最多,还涉及到AI知识,如果有兴趣可以自己了解一下
这里为了在播放背景音乐的同时能播放其他生效用了最简单的一种多线程如

thread t1(load_play_audio,("tankfire1.mp3"),0,1000);
	t1.detach();

详情见C++ 多线程–STL库 总结版 (详细)

###2P模式 _2pmode.cpp

#include"game.h"
using namespace std;

void _2pmode(bool* if_construction)					//2p模式主函数
{
	int level = 1;
	int if_win = 0;									//
	load_play_audio("bk.mp3", 1, 1000);
	IMAGE bk;										//保存游戏结束时的界面用于播放后续动画
	_1p.x = 280, _1p.y = 816, _1p.vx = 5, _1p.dir = 0, _1p.life = 5, _1p.enemy_tank = 0;//设定1p各项属性
	loadimagetank(&_1p, "1p");
	_2p.x = 600, _2p.y = 816, _2p.vx = 5, _2p.dir = 0, _2p.life = 5, _2p.enemy_tank = 2;
	loadimagetank(&_2p, "2p");
	tank_enemy.push_back(_1p);
	tank_enemy.push_back(_2p);
	if (*if_construction)
		load_map(0), * if_construction = false;
	else
		load_map(level);
	int frame = 0;							//记录游戏周期数
	while (1)								//每循环一次代表一个游戏周期
	{
		time0 = GetTickCount();
		if (time0 > timetrigger)
		{
			frame++;

			timetrigger = time0 + 40;
			if_win = gameend(0);
			if (if_win == 0)
			{
				BeginBatchDraw();
				while (total_enm > 0 && enm < max_enm)
				{
					if (create_enm())
					{
						total_enm--;
						enm++;
					}
					else
						break;
				}
				for (int i = 2; i + tank_enemy.begin() != tank_enemy.end(); i++) {
					enemy_move(&tank_enemy[i], i);											//这里还要加转向修改
				}
				PrintScore(tank_enemy[0].life, tank_enemy[1].life);
				drawmap(map);
				put_enmtank();
				putplayertank(&tank_enemy[0]);
				putplayertank(&tank_enemy[1]);
				if (tank_enemy[1].enemy_tank == 2)
				{
					thread t1(handlekeys,&tank_enemy[1],1);
					t1.detach();
				}
				handlekeys(&tank_enemy[0],0);
				checkgrass();
				checkbullet();
				drawbullet();
				boom_draw();
				if (frame % 2 == 0)
					boom_update();
				if (frame % 8 == 0)
				{
					Tank mid;
					mid = rand() % 2 == 1 ? tank_enemy[0] : tank_enemy[1];
					for (int i = 2; i + tank_enemy.begin() != tank_enemy.end(); i++) {
						if (tank_enemy[i].stop) {
							tank_enemy[i].stop--;
							continue;
						}
						if (!tank_enemy[i].type && !tank_enemy[i].stop) {
							AI_attack(tank_enemy[i].x, tank_enemy[i].y, i, mid.x, mid.y, mid.dir);
							if (!(rand() % 10))
								tank_enemy[i].stop = 3;
						}
						else if (tank_enemy[i].type == 1 && !tank_enemy[i].stop) {
							AI_terminator(tank_enemy[i].x, tank_enemy[i].y, tank_enemy[i].dir, i);
						}
					}

				}
				if (frame == 50)
				{
					frame = 0;
				}
				EndBatchDraw();

			}
			else
			{
				load_play_audio("bk.mp3", 2, 1000);
				drawmap(map);
				put_enmtank();
				putplayertank(&tank_enemy[0]);
				getimage(&bk, 0, 0, 960, 864);
				gameend_play(if_win, bk);
				SaveScore(onetankscore, twotankscore, 2);
				Sleep(200);
				while (1)
				{
					if (GetAsyncKeyState(' ') < 0)
						break;
				}
				break;
			}
		}

	}
	
}

2p与1p相比主要是多了个对2p的操控,其他基本没变

结语

做这个小游戏前前后后花了差不多2个月,通过实际的操作是真真切切的体会到了做一个项目的辛苦,但也确实感到了乐趣,尤其是测试时各种神奇的bug虽然让人生气,但有时也让人发笑,看着编完之后10多MB的文件夹,我也是深刻感觉到了过去那些做FC游戏的大佬的厉害。这篇文章对代码也没太多讲解,也是希望大家能更多的靠自己思考解决问题(其实是因为太懒了),文章里提到的各种东西都是我们自己在网上仔细查了之后编出来的,这里我们直接给出了相应链接,省去了大家查询时间,但同时也希望大家能仔细思考,多多理解。最后,因为这是本人第一次发帖,没有经验,可能有一些遗漏,如果问题比较大,我后续会找时间更新。谢谢大家。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值