C++游戏开发——坦克大战

 

引言:

就是练C++而已的。

 代码:

工具类

lag.h

#pragma once

#include <time.h>
#include <vector>
#include <string>
#include <conio.h>
#include <stdlib.h>
#include <iostream>
#include <windows.h>
#include <graphics.h>
#include <mmsystem.h>
#pragma comment(lib,"winmm.lib")        // 播放音频

using namespace std;

/*
功能:窗口居中
参数:hWnd-窗口句柄
*/
void myCenterWindow(HWND hWnd);

/*
功能:得到某范围内的随机整数
参数:min - 最小值
     max - 最大值
返回:某范围内的随机整数
*/
int myRandom(int min, int max);

/*
功能:定时器
参数:interval - 延时间隔(毫秒)
     id - 编号 (0-max)
返回:true-已到时,false-未到时
*/
bool myTimer(int interval, int id);

/*
功能:播放音频
参数:fileName - 音频文件
     repeat - 是否循环播放(true-循环,false-不循环)
返回:无
*/
void myPlayAudio(const string& fileName, bool repeat = false);

/*
功能:判断某键是否被按下
参数:keyCode - 键值
返回:true-按下,false-未按下
*/
bool myKeyDown(int keyCode);

/*
功能:判断两个矩形是否相交
参数:x1 - 第一个矩形的左上角X坐标
     y1 - 第一个矩形的左上角Y坐标
     w1 - 第一个矩形的宽度
     h1 - 第一个矩形的高度
     x2 - 第二个矩形的左上角X坐标
     y2 - 第二个矩形的左上角Y坐标
     w2 - 第二个矩形的宽度
     h2 - 第二个矩形的高度
返回:true-相交,false-不相交
*/
bool myRectIntersectRect(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);

/*
功能:绘制透明图片
参数:dstX - 目的X坐标
     dstY - 目的Y坐标
     pSrcImg - 源图像指针
     winWidth - 窗口宽度(判断图片位置是否超出窗口范围,不录则默认为0,表示该参数不用)
     winHeight - 窗口高度(判断图片位置是否超出窗口范围,不录则默认为0,表示该参数不用)
返回:无
*/
void myDrawImage(int dstX, int dstY, IMAGE* pSrcImg, int winWidth = 0, int winHeight = 0);

/*
功能:绘制字符串
参数:text - 字符串内容
     x - X坐标
     y - Y坐标
返回:无
*/
void myDrawString(int x, int y, const string& text);

lag.cpp

#include "lag.h"

/*
功能:窗口居中
参数:hWnd-窗口句柄
*/
void myCenterWindow(HWND hWnd)
{
	int screenWidth;		// 屏幕宽度
	int screenHeight;		// 屏幕高度
	RECT rect;				// 矩形

	// 得到屏幕尺寸
	screenWidth = GetSystemMetrics(SM_CXSCREEN);
	screenHeight = GetSystemMetrics(SM_CYSCREEN);

	// 得到窗口尺寸
	GetWindowRect(hWnd, &rect);

	// 重新设置窗口尺寸
	rect.left = (screenWidth - (rect.right - rect.left)) / 2;
	rect.top = (screenHeight - (rect.bottom - rect.top)) / 3;

	// 移动窗口到屏幕中间
	SetWindowPos(hWnd, HWND_TOP, rect.left, rect.top, rect.right, rect.bottom, SWP_NOSIZE);
}

/*
功能:得到某范围内的随机整数
参数:min - 最小值
	 max - 最大值
返回:某范围内的随机整数
备注:公式:min + rand() % (max - min + 1)
	 原理:rand() % m => 返回[0-m)的随机数
*/
int myRandom(int min, int max)
{
	// 生成随机种子(必须在原有毫秒时间的基础上再加随机值,否则在类似for循环中会出现同一种子值的现象)
	srand((unsigned int)time(NULL) + (unsigned)rand());

	return (int)(min + rand() % (max - min + 1));
}

/*
功能:定时器
参数:interval - 延时间隔(毫秒)
	 id - 编号 (0-max)
返回:true-已到时,false-未到时
*/
bool myTimer(int interval, int id)
{
	// 静态vector数组(默认数组元素为5,值为0)
	static vector<unsigned long long> vectorLastTimeForMyTimer(5, 0);

	// 根据编号自动扩容
	if (id < 0) { id = 0; }
	if ((int)vectorLastTimeForMyTimer.size() <= id) { vectorLastTimeForMyTimer.resize(id + 1, 0); }

	// 得到当前毫秒并判断是否到时
	unsigned long long currentTime = GetTickCount64();
	if (vectorLastTimeForMyTimer[id] == 0)		// 未初始化呢
	{
		vectorLastTimeForMyTimer[id] = currentTime;
		return false;
	}
	else
	{
		int addTime = (int)(currentTime - vectorLastTimeForMyTimer[id]);
		if (addTime >= interval)
		{
			vectorLastTimeForMyTimer[id] = currentTime;
			return true;
		}
	}

	return false;
}

/*
功能:播放音频
参数:fileName - 音频文件
	 repeat - 是否循环播放(true-循环,false-不循环)
返回:无
*/
void myPlayAudio(const string& fileName, bool repeat)
{
	string command = "play " + fileName;
	if (repeat) { command += " repeat"; }
	mciSendString(command.c_str(), 0, 0, 0);
}

/*
功能:判断某键是否被按下
参数:keyCode - 键值
返回:true-按下,false-未按下
*/
bool myKeyDown(int keyCode)
{
	return (GetAsyncKeyState(keyCode) & 0x8000);
}

/*
功能:判断两个矩形是否相交
参数:x1 - 第一个矩形的左上角X坐标
	 y1 - 第一个矩形的左上角Y坐标
	 w1 - 第一个矩形的宽度
	 h1 - 第一个矩形的高度
	 x2 - 第二个矩形的左上角X坐标
	 y2 - 第二个矩形的左上角Y坐标
	 w2 - 第二个矩形的宽度
	 h2 - 第二个矩形的高度
返回:true-相交,false-不相交
*/
bool myRectIntersectRect(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2)
{
	if (x1 > x2 + w2) { return false; }
	if (x2 > x1 + w1) { return false; }
	if (y1 > y2 + h2) { return false; }
	if (y2 > y1 + h1) { return false; }

	return true;
}

/*
功能:载入图片并过滤透明部分(做位运算)
参数:picture_x - 载入图片X坐标
	 picture_y - 载入图片Y坐标
	 picture - 载入图片
返回:无
*/
void myDrawImageAlpha(int  picture_x, int picture_y, IMAGE* picture)
{
	DWORD* dst = GetImageBuffer();						// GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
	DWORD* draw = GetImageBuffer();
	DWORD* src = GetImageBuffer(picture);				// 获取picture的显存指针
	int picture_width = picture->getwidth();			// 获取picture的宽度,EASYX自带
	int picture_height = picture->getheight();			// 获取picture的高度,EASYX自带
	int graphWidth = getwidth();						// 获取绘图区的宽度,EASYX自带
	int graphHeight = getheight();						// 获取绘图区的高度,EASYX自带
	int dstX = 0;										// 在显存里像素的角标

	// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
	for (int iy = 0; iy < picture_height; iy++)
	{
		for (int ix = 0; ix < picture_width; ix++)
		{
			int srcX = ix + iy * picture_width;			// 在显存里像素的角标
			int sa = ((src[srcX] & 0xff000000) >> 24);	// 0xAArrggbb;AA是透明度
			int sr = ((src[srcX] & 0xff0000) >> 16);	// 获取RGB里的R
			int sg = ((src[srcX] & 0xff00) >> 8);		// G
			int sb = src[srcX] & 0xff;					// B
			if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
			{
				dstX = (ix + picture_x) + (iy + picture_y) * graphWidth;		// 在显存里像素的角标
				int dr = ((dst[dstX] & 0xff0000) >> 16);
				int dg = ((dst[dstX] & 0xff00) >> 8);
				int db = dst[dstX] & 0xff;
				draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)	// 公式: Cp=αp*FP+(1-αp)*BP  ; αp=sa/255 , FP=sr , BP=dr
					| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)			// αp=sa/255 , FP=sg , BP=dg
					| (sb * sa / 255 + db * (255 - sa) / 255);					// αp=sa/255 , FP=sb , BP=db
			}
		}
	}
}

/*
功能:绘制透明图片
参数:dstX - 目的X坐标
	 dstY - 目的Y坐标
	 pSrcImg - 源图像指针
	 winWidth - 窗口宽度(判断图片位置是否超出窗口范围,不录则默认为0,表示该参数不用)
	 winHeight - 窗口高度(判断图片位置是否超出窗口范围,不录则默认为0,表示该参数不用)
返回:无
*/
void myDrawImage(int dstX, int dstY, IMAGE* pSrcImg, int winWidth, int winHeight)
{
	IMAGE imgTmp;
	int newImgX = 0;
	int newImgY = 0;
	int newImgWidth = pSrcImg->getwidth();
	int newImgHeight = pSrcImg->getheight();
	int flag = 0;

	// 图片完全不在窗口中
	if (dstX <= -pSrcImg->getwidth()) { return; }
	if (winWidth > 0 && dstX >= winWidth) { return; }
	if (dstY <= -pSrcImg->getheight()) { return; }
	if (winHeight > 0 && dstY >= winHeight) { return; }

	// 处理X坐标
	if (dstX < 0)   // 左边界
	{
		newImgX = -dstX;
		newImgWidth = pSrcImg->getwidth() + dstX;
		dstX = 0;
		flag = 1;
	}
	else if (winWidth > 0 && dstX > winWidth - pSrcImg->getwidth())     // 右边界
	{
		newImgWidth = winWidth - dstX;
		flag = 1;
	}

	// 处理Y坐标
	if (dstY < 0)       // 上边界
	{
		newImgY = -dstY;
		newImgHeight = pSrcImg->getheight() + dstY;
		dstY = 0;
		flag = 1;
	}
	else if (winHeight > 0 && dstY > winHeight - pSrcImg->getheight())      // 下边界
	{
		newImgHeight = winHeight - dstY;
		flag = 1;
	}

	// 处理图片变动
	if (flag == 1)
	{
		SetWorkingImage(pSrcImg);   // 设定pSrcImg为当前的绘图设备
		getimage(&imgTmp, newImgX, newImgY, newImgWidth, newImgHeight);      // 从当前绘图设备获取图像(即截取pSrcImg的要显示部分内容放到imgTmp中)
		SetWorkingImage();          // 恢复默认绘图设备
		pSrcImg = &imgTmp;
	}

	// 开始输出透明位图
	myDrawImageAlpha(dstX, dstY, pSrcImg);
}

/*
功能:绘制字符串
参数:text - 字符串内容
	 x - X坐标
	 y - Y坐标
返回:无
*/
void myDrawString(int x, int y, const string& text)
{
	outtextxy(x, y, text.c_str());
}

/*
功能:绘制血条
参数:x - 血条X坐标
	 y - 血条Y坐标
	 width - 血条宽度
	 height - 血条高度
	 percent - 血条比例
返回:无
*/
void myDrawBloodBar(int x, int y, int width, int height, float percent);

/*
功能:绘制血条
参数:x - 血条X坐标
	 y - 血条Y坐标
	 width - 血条宽度
	 height - 血条高度
	 percent - 血条比例
返回:无
*/
void myDrawBloodBar(int x, int y, int width, int height, float percent)
{
	// 记录原来的状态,以便后面恢复
	COLORREF fillColor = getfillcolor();
	COLORREF getColor = getcolor();

	if (percent < 0) { percent = 0.0; }

	setfillcolor(YELLOW);
	solidrectangle(x, y, x + width, y + height);
	setfillcolor(RED);
	solidrectangle(x, y, (int)(x + width * percent), y + height);
	setcolor(WHITE);
	rectangle(x, y, x + width, y + height);

	// 恢复原来的状态
	setfillcolor(fillColor);
	setcolor(getColor);
}

方块类 

Block.h

#pragma once

#include "lag.h"

// 方块类
class Block
{
private:
	IMAGE imgWall;			// 墙块图片
	IMAGE imgIron;			// 铁块图片
	IMAGE imgHome;			// 老巢图片
	int(*map)[26];			// 当前地图
public:

	// 构造函数
	Block();

	// 绘制方块
	void draw();

};

Block.cpp

#include "Block.h"
#include "GameMap.h"
#include "define.h"

// 构造函数
Block::Block()
{
	// 加载图片
	loadimage(&imgWall, "./resources/image/wall.gif");
	loadimage(&imgIron, "./resources/image/iron.gif");
	loadimage(&imgHome, "./resources/image/home.jpg");
	
	// 得到当前地图
	map = GameMap::getMap();
}

// 绘制方块
void Block::draw()
{
	// 绘制墙块与铁块
	for (int i = 0; i < 26; i++)
	{
		for (int j = 0; j < 26; j++)
		{
			int value = map[i][j];
			if (value > 0)
			{
				if (value == WALL)			// 墙块
				{
					putimage(j * BLOCK_SIZE, i * BLOCK_SIZE, &imgWall);
				}
				else if (value == IRON)	// 铁块
				{
					putimage(j * BLOCK_SIZE, i * BLOCK_SIZE, &imgIron);
				}
			}
		}
	}

	// 绘制老巢
	myDrawImage(12 * BLOCK_SIZE, 24 * BLOCK_SIZE, &imgHome);
}

爆炸类

Bomb.h

#pragma once
#include "define.h"
#include "lag.h"

// 爆炸类
class Bomb
{
private:
	static IMAGE* imgBombs[5];				// 爆炸图片

public:
	int x = 0;								// 爆炸中心点X坐标
	int y = 0;								// 爆炸中心点Y坐标
	int frameIndex = -1;					// 爆炸图片帧数
	int maxFrame = 5;						// 最大图片帧数
	int size = BLOCK_SIZE * 2;				// 爆炸尺寸
	int status = BOMB_STATUS_FREE;			// 爆炸状态

public:

	// 构造函数
	Bomb();

	// 绘制爆炸
	void draw();
};

Bomb.cpp

#include "Bomb.h"

IMAGE* Bomb::imgBombs[5] = {NULL};				// 初始化爆炸图片

// 构造函数
Bomb::Bomb()
{
	// 加载图片
	if (imgBombs[0] == NULL)
	{
		IMAGE imgTmp;
		loadimage(&imgTmp, "./resources/image/bomb.png", size * 5, size);
		SetWorkingImage(&imgTmp);				// 设定当前绘图目标为imgTmp
		for (int i = 0; i < 5; i++)
		{
			imgBombs[i] = new IMAGE;
			getimage(imgBombs[i], i * size, 0, size, size);
		}
		SetWorkingImage();						// 设置绘图目标为绘图窗口
	}
}

// 绘制爆炸
void Bomb::draw()
{
	myDrawImage(x - size / 2 + 6, y - size / 2 + 6, imgBombs[frameIndex],GAME_WIDTH,GAME_HEIGHT);	// 得考虑子弹的尺寸
}

子弹类

Bullet.h

#pragma once

#include "lag.h"
#include "define.h"

// 子弹类
class Bullet
{
private:
	static IMAGE* imgBullets[4];			// 子弹图片

public:
	int x = 0;								// X坐标
	int y = 0;								// Y坐标
	int direction = 0;						// 方向
	int speed = 6;							// 速度
	int owner = 0;							// 拥有者
	int status = BULLET_STATUS_FREE;		// 状态

public:

	// 构造函数
	Bullet();

	// 子弹绘制
	void draw();

	// 子弹运行
	void run();

};

Bullet.cpp

#include "Bullet.h"

IMAGE* Bullet::imgBullets[4] = {NULL};			// 初始化子弹图片

// 构造函数
Bullet::Bullet()
{
	// 加载子弹图片
	if (imgBullets[0] == NULL)
	{
		IMAGE imgTmp;
		loadimage(&imgTmp, "./resources/image/bullet.png", BULLET_SIZE * 4, BULLET_SIZE);
		SetWorkingImage(&imgTmp);				// 设定当前绘图目标为imgTmp
		for (int i = 0; i < 4; i++)
		{
			imgBullets[i] = new IMAGE;
			getimage(imgBullets[i], i * BULLET_SIZE, 0, BULLET_SIZE, BULLET_SIZE);
		}
		SetWorkingImage();						// 设置绘图目标为绘图窗口
	}
}

// 子弹绘制
void Bullet::draw()
{
	myDrawImage(this->x, this->y, imgBullets[this->direction], GAME_WIDTH, GAME_HEIGHT);
}

// 子弹运行
void Bullet::run()
{
	switch (this->direction)
	{
		case TANK_DIRECTION_UP:
			if (this->y - this->speed >= 0)
			{
				this->y -= this->speed;
			}
			else
			{
				this->status = BULLET_STATUS_FREE;
			}
			break;
		case TANK_DIRECTION_DOWN:
			if (this->y + BULLET_SIZE + this->speed <= GAME_HEIGHT)
			{
				this->y += this->speed;
			}
			else
			{
				this->status = BULLET_STATUS_FREE;
			}
			break;
		case TANK_DIRECTION_LEFT:
			if (this->x >= this->speed)
			{
				this->x -= this->speed;
			}
			else
			{
				this->status = BULLET_STATUS_FREE;
			}
			break;
		case TANK_DIRECTION_RIGHT:
			if (this->x + BLOCK_SIZE + this->speed <= GAME_WIDTH)
			{
				this->x += this->speed;
			}
			else
			{
				this->status = BULLET_STATUS_FREE;
			}
			break;
	}
}

宏定义

define.h

#pragma once

// 主窗口宏定义
#define TITLE "坦克大战"						// 窗口标题
#define WIN_WIDTH 570						// 窗口宽度
#define WIN_HEIGHT 468						// 窗口高度
#define GAME_WIDTH 468						// 游戏宽度
#define GAME_HEIGHT 468						// 游戏高度
#define INTERVAL_REFRESH 10					// 界面刷新间隔
#define TIMERID_REFRESH 0					// 界面刷新ID
#define GAME_STATUS_RUN	0					// 游戏状态(运行)
#define GAME_STATUS_WIN 1					// 游戏状态(胜利)
#define GAME_STATUS_OVER 2					// 游戏状态(失败)
#define INTERVAL_SCORE 500					// 分数刷新间隔
#define TIMERID_SCORE 8						// 分数刷新ID

// 块宏定义
#define BLANK 0								// 空地
#define WALL 1								// 墙块
#define IRON 2								// 铁块
#define HOME 9								// 老巢
#define BLOCK_SIZE 18						// 方块尺寸

// 坦克宏定义
#define TANK_OWNER_HERO 8					// 我方坦克
#define TANK_OWNER_ENEMY 7					// 敌方坦克
#define TANK_DIRECTION_UP 0					// 坦克方向(向上)
#define TANK_DIRECTION_LEFT 1				// 坦克方向(向左)
#define TANK_DIRECTION_DOWN 2				// 坦克方向(向下)
#define TANK_DIRECTION_RIGHT 3				// 坦克方向(向右)
#define TANK_STATUS_FREE 0					// 坦克状态(空闲)
#define TANK_STATUS_RUN 1					// 坦克状态(运行)
#define INTERVAL_TANKMOVE 10				// 坦克移动进程刷新间隔
#define TIMERID_TANKMOVE 4					// 坦克移动进程刷新ID
#define INTERVAL_CREATEENEMY 5000			// 敌方坦克投放刷新间隔
#define TIMERID_CREATEENEMY 5				// 敌方坦克投放刷新ID
#define INTERVAL_MOVEENEMY 300				// 敌方坦克移动刷新间隔
#define TIMERID_MOVEENEMY 6					// 敌方坦克移动刷新ID

// 子弹宏定义
#define INTERVAL_BULLET_SHOOT 500			// 子弹射击间隔
#define TIMERID_BULLET_SHOOT 1				// 子弹射击ID
#define INTERVAL_BULLET_RUN 10				// 子弹运行间隔
#define TIMERID_BULLET_RUN 2				// 子弹运行ID
#define BULLET_STATUS_FREE 0				// 子弹状态(空闲)
#define BULLET_STATUS_RUN 1					// 子弹状态(运行)
#define BULLET_SIZE 9						// 子弹尺寸

// 爆炸宏定义
#define INTERVAL_BOMB 50					// 爆炸刷新间隔
#define TIMERID_BOMB 3						// 爆炸刷新ID
#define BOMB_STATUS_FREE 0					// 爆炸状态(空闲)
#define BOMB_STATUS_RUN 1					// 爆炸状态(运行)

// 星星宏定义
#define INTERVAL_STAR 100					// 星星刷新间隔
#define TIMERID_STAR 7						// 星星刷新ID
#define STAR_STATUS_FREE 0					// 星星状态(空闲)
#define STAR_STATUS_RUN 1					// 星星状态(运行)

游戏地图类

GameMap.h

#pragma once

#define LEVEL_TOTAL 2						// 总关卡数

// 游戏地图
class GameMap
{
private:
	static int maps[LEVEL_TOTAL][26][26];	// 各关地图
	static int level;						// 当前关数
	static int enemyTankNum[LEVEL_TOTAL];	// 当前关敌方坦克数

public:

	// 设置关数
	static void setLevel(int level);

	// 得到最大关数
	static int getMaxLevel();

	// 得到当前关敌方坦克数
	static int getEnemyTankNum(int level);

	// 得到当前关地图
	static int(*getMap())[26];

};

GameMap.cpp

#include "GameMap.h"

// 各关地图初始化
int GameMap::maps[LEVEL_TOTAL][26][26] =
{
    // 第1关地图
    {
        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,2,2,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,2,2,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
        {0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
        {1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1},
        {2,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2},
        {0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0},
        {0,0,0,0,0,0,0,0,0,0,0,1,9,9,1,0,0,0,0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0,0,0,0,1,9,9,1,0,0,0,0,0,0,0,0,0,0,0}
    },
    // 第2关地图
    {
        {0,0,0,0,0,0,2,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,2,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0},
        {0,0,1,1,0,0,2,2,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,2,2,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
        {0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
        {0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0},
        {0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0},
        {0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,1,1,0,0,1,1,2,2},
        {0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,1,1,0,0,1,1,2,2},
        {0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,0,0,0,0},
        {0,0,1,1,1,1,1,1,0,0,0,0,0,0,2,2,0,0,0,0,0,0,1,1,0,0},
        {0,0,1,1,1,1,1,1,0,0,0,0,0,0,2,2,0,0,0,0,0,0,1,1,0,0},
        {0,0,0,0,0,0,2,2,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {0,0,0,0,0,0,2,2,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
        {2,2,1,1,0,0,2,2,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0},
        {2,2,1,1,0,0,2,2,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
        {0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
        {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,0,1,9,9,1,0,0,0,1,1,1,1,1,1,0,0},
        {0,0,1,1,0,0,1,1,0,0,0,1,9,9,1,0,0,0,1,1,1,1,1,1,0,0}
    }
    // 其他关地图...
};

// 当前关卡初始化
int GameMap::level = 0;

// 当前关敌方坦克数初始化
int GameMap::enemyTankNum[LEVEL_TOTAL] = { 16,20 };

// 设置关数
void GameMap::setLevel(int level)
{
	GameMap::level = level;
}

// 得到最大关数
int GameMap::getMaxLevel()
{
    return LEVEL_TOTAL;
}

// 得到当前关敌方坦克数
int GameMap::getEnemyTankNum(int level)
{
    return GameMap::enemyTankNum[level];
}

// 得到当前关地图
int(*GameMap::getMap())[26]
{
    return GameMap::maps[GameMap::level];
}

星星类

Star.h

#pragma once

#include "define.h"
#include "lag.h"

// 星星类
class Star
{
private:
	static IMAGE* imgStars[4];				// 星星图片
	unsigned long long lastTime;			// 上次时间

public:
	int row = 0;							// 行坐标
	int column = 0;							// 列坐标
	int status = STAR_STATUS_FREE;			// 星星状态
	int frameIndex = -1;					// 星星图片帧数
	int maxFrame = 4;						// 星星图片帧数
	int size = BLOCK_SIZE * 2;				// 星星尺寸
	
public:

	// 构造函数
	Star();

	// 绘制星星
	void draw();

};

Star.cpp

#include "Star.h"

IMAGE* Star::imgStars[4] = {NULL};

// 构造函数
Star::Star()
{
	// 加载图片
	if (imgStars[0] == NULL)
	{
		IMAGE imgTmp;
		loadimage(&imgTmp, "./resources/image/star.png", size * 4, size);
		SetWorkingImage(&imgTmp);				// 设定当前绘图目标为imgTmp
		for (int i = 0; i < 4; i++)
		{
			imgStars[i] = new IMAGE;
			getimage(imgStars[i], i * size, 0, size, size);
		}
		SetWorkingImage();						// 设置绘图目标为绘图窗口
	}

	// 计时开始
	this->lastTime = GetTickCount64();
}

// 绘制星星
void Star::draw()
{
	myDrawImage(column * BLOCK_SIZE,row * BLOCK_SIZE, imgStars[frameIndex]);
}

坦克类

Tank.h

#pragma once

#include "lag.h"
#include "Bullet.h"

// 坦克类
class Tank
{
private:
	int owner;							// 坦克拥有者
	int(*map)[26];						// 关卡地图
	static IMAGE* imgHero[4][4][2];		// 我方坦克图片([装甲][方向][履带])
	static IMAGE* imgEnemy[4][4][2];	// 敌方坦克图片([装甲][方向][履带])
	vector<Bullet> bulletPool;			// 子弹池
	unsigned long long lastTime;		// 上次时间

public:
	int x;								// 坦克左上角X坐标
	int y;								// 坦克左上角Y坐标
	int row;							// 坦克所在行
	int column;							// 坦克所在列
	int oldRow;							// 坦克上次所在行
	int oldColumn;						// 坦克上次所在列
	int direction;						// 坦克方向
	int speed = 2;						// 坦克速度
	int originalArmor = 0;				// 原始装甲
	int armor = 0;						// 当前装甲(共4层)
	int status = TANK_STATUS_FREE;		// 坦克状态
	bool track = false;					// 履带切换

private:

	// 坦克是否可以移动
	bool moveValid(int direction);

public:

	// 有参构造函数
	Tank(int tankOwner, int tankRow, int tankColumn, int tankDirection);

	// 坦克绘制
	void draw();

	// 坦克移动
	bool move(int direction);

	// 坦克射击
	void shoot();

	// 坦克坐标映射到地图
	void toMap();

	// 坦克重置
	void reset();

	// 得到子弹池
	vector<Bullet>& getBulletPool();

};

Tank.cpp

#include "Tank.h"
#include "GameMap.h"
#include "define.h"

IMAGE* Tank::imgHero[4][4][2] = {NULL};				// 初始化我方坦克图片
IMAGE* Tank::imgEnemy[4][4][2] = {NULL};			// 初始化敌方坦克图片

// 有参构造函数
Tank::Tank(int owner, int row, int column, int direction)
{
	// 参数初始化
	this->owner = owner;
	this->row = row;
	this->column = column;
	this->oldRow = this->row;
	this->oldColumn = this->column;
	this->x = this->column * BLOCK_SIZE;
	this->y = this->row * BLOCK_SIZE;
	this->direction = direction;
	this->map = GameMap::getMap();

	// 加载敌我双方坦克图片(图片每一行装甲不同,这里没用装甲)
	if (imgHero[0][0][0] == NULL)
	{
		// 加载敌我坦克图片
		IMAGE imgTmp;
		loadimage(&imgTmp, "./resources/image/tank.png", BLOCK_SIZE * 16, BLOCK_SIZE * 16);			// 加载时扩大到合适尺寸,剪裁时就正好大小了
		SetWorkingImage(&imgTmp);			// 切换到绘图工作区
		for (int ar = 0; ar < 4; ar++)
		{
			for (int dir = 0; dir < 4; dir++)
			{
				for (int tr = 0; tr < 2; tr++)
				{
					// 我方坦克
					imgHero[ar][dir][tr] = new IMAGE;
					getimage(imgHero[ar][dir][tr], dir * BLOCK_SIZE * 4 + tr * BLOCK_SIZE * 2 - 1, ar * BLOCK_SIZE * 2, BLOCK_SIZE * 2, BLOCK_SIZE * 2);
					// 敌方坦克
					imgEnemy[ar][dir][tr] = new IMAGE;
					getimage(imgEnemy[ar][dir][tr], dir * BLOCK_SIZE * 4 + tr * BLOCK_SIZE * 2 - 1, BLOCK_SIZE * 8 + ar * BLOCK_SIZE * 2, BLOCK_SIZE * 2, BLOCK_SIZE * 2);
				}
			}
		}
		SetWorkingImage();					// 切换回窗口工作区
	}

	// 计时开始
	this->lastTime = GetTickCount64();
}

// 坦克绘制
void Tank::draw()
{
	// 绘制我方坦克
	if (this->owner == TANK_OWNER_HERO && this->status == TANK_STATUS_RUN)
	{
		myDrawImage(this->x, this->y, imgHero[this->armor][this->direction][this->track]);
	}
	// 绘制敌方坦克
	if (this->owner == TANK_OWNER_ENEMY && this->status == TANK_STATUS_RUN)
	{
		myDrawImage(this->x, this->y, imgEnemy[this->armor][this->direction][this->track]);
	}
}

// 坦克是否可以移动
bool Tank::moveValid(int direction)
{
	switch (direction)
	{
		case TANK_DIRECTION_UP:
			if (row == 0) { return false; }
			if (map[row - 1][column] > 0) { return false; }
			if (map[row - 1][column + 1] > 0) { return false; }
			break;
		case TANK_DIRECTION_DOWN:
			if (row == 24) { return false; }
			if (map[row + 2][column] > 0) { return false; }
			if (map[row + 2][column + 1] > 0) { return false; }
			break;
		case TANK_DIRECTION_LEFT:
			if (column == 0) { return false; }
			if (map[row][column - 1] > 0) { return false; }
			if (map[row + 1][column - 1] > 0) { return false; }
			break;
		case TANK_DIRECTION_RIGHT:
			if (column == 24) { return false; }
			if (map[row][column + 2] > 0) { return false; }
			if (map[row + 1][column + 2] > 0) { return false; }
			break;
	}
	return true;
}

// 坦克移动
bool Tank::move(int direction)
{
	// 如果坦克移动进程未完成则禁止再次移动
	if (this->oldRow != this->row) { return false; }
	if (this->oldColumn != this->column) { return false; }

	if (this->direction == direction)			// 方向相同则前进
	{
		//  判断是否可以移动
		if (!moveValid(direction)) { return false; }

		// 开始移动
		switch (direction)
		{
			case TANK_DIRECTION_UP:
				map[row + 1][column] = 0;
				map[row + 1][column + 1] = 0;
				map[row - 1][column] = owner;
				map[row - 1][column + 1] = owner;
				oldRow = row;
				row--;
				break;
			case TANK_DIRECTION_DOWN:
				map[row][column] = 0;
				map[row][column + 1] = 0;
				map[row + 2][column] = owner;
				map[row + 2][column + 1] = owner;
				oldRow = row;
				row++;
				break;
			case TANK_DIRECTION_LEFT:
				map[row][column + 1] = 0;
				map[row + 1][column + 1] = 0;
				map[row][column - 1] = owner;
				map[row + 1][column - 1] = owner;
				oldColumn = column;
				column--;
				break;
			case TANK_DIRECTION_RIGHT:
				map[row][column] = 0;
				map[row + 1][column] = 0;
				map[row][column + 2] = owner;
				map[row + 1][column + 2] = owner;
				oldColumn = column;
				column++;
				break;
		}
	}
	else    // 方向不同,仅调整方向不前进
	{
		this->direction = direction;
	}

	return true;
}

// 坦克射击
void Tank::shoot()
{
	// 射击冷却未到时间禁止发射
	unsigned long long currentTime = GetTickCount64();
	int addTime = (int)(currentTime - this->lastTime);
	if (addTime >= INTERVAL_BULLET_SHOOT)
	{
		this->lastTime = currentTime;
	}
	else
	{
		return;
	}
	
	// 在子弹池中寻找空闲的子弹
	Bullet *bullet = nullptr;
	int len = this->bulletPool.size();
	for (int i = 0; i < len; i++)
	{
		if (this->bulletPool[i].status == BULLET_STATUS_FREE)
		{
			bullet = &this->bulletPool[i];
			break;
		}
	}
  	if (bullet == nullptr)			// 没有就增加一个
	{
		Bullet newBullet;
		newBullet.owner = this->owner;
		this->bulletPool.push_back(newBullet);	// 浅拷贝
		bullet = &bulletPool[len];
	}

	// 设置子弹位置
	bullet->direction = this->direction;
	switch (this->direction)
	{
		case TANK_DIRECTION_UP:
			bullet->x = this->column * BLOCK_SIZE + BLOCK_SIZE - BULLET_SIZE / 2;
			bullet->y = this->row * BLOCK_SIZE - BULLET_SIZE - 4;
			break;
		case TANK_DIRECTION_DOWN:
			bullet->x = this->column * BLOCK_SIZE + BLOCK_SIZE - BULLET_SIZE / 2;
			bullet->y = this->row * BLOCK_SIZE + 2 * BLOCK_SIZE + 4;
			break;
		case TANK_DIRECTION_LEFT:
			bullet->x = this->column * BLOCK_SIZE - BULLET_SIZE - 4;
			bullet->y = this->row * BLOCK_SIZE + BLOCK_SIZE - BULLET_SIZE / 2;
			break;
		case TANK_DIRECTION_RIGHT:
			bullet->x = this->column * BLOCK_SIZE + 2 * BLOCK_SIZE + 4;
			bullet->y = this->row * BLOCK_SIZE + BLOCK_SIZE - BULLET_SIZE / 2;
			break;
	}

	// 设置子弹状态
	bullet->status = BULLET_STATUS_RUN;

	// 我方坦克发出射击声音
	if (owner == TANK_OWNER_HERO){myPlayAudio("./resources/audio/shoot.mp3");}
	
}

// 坦克坐标映射到地图
void Tank::toMap()
{
	map[row][column] = owner;
	map[row][column + 1] = owner;
	map[row + 1][column] = owner;
	map[row + 1][column + 1] = owner;
}

// 坦克重置
void Tank::reset()
{
	map[row][column] = 0;
	map[row][column + 1] = 0;
	map[row + 1][column] = 0;
	map[row + 1][column + 1] = 0;
	if (owner == TANK_OWNER_HERO)
	{
		this->row = 24;
		this->column = 8;
		this->oldRow = this->row;
		this->oldColumn = this->column;
		this->x = this->column * BLOCK_SIZE;
		this->y = this->row * BLOCK_SIZE;
		this->direction = TANK_DIRECTION_UP;
		this->armor = 3;
	}
	else
	{
		this->row = 0;
		this->oldRow = 0;
		this->column = 0;
		this->oldColumn = 0;
		this->x = 0;
		this->y = 0;
	}
	this->status = TANK_STATUS_FREE;
}

// 得到子弹池
vector<Bullet>& Tank::getBulletPool()
{
	return this->bulletPool;
}

我方坦克类

Hero.h

#pragma once

#include "Tank.h"

// 我方坦克类
class Hero : public Tank
{

public:

	// 构造函数
	Hero(int tankRow, int tankColumn, int tankDirection);

};

Hero.cpp

#include "Hero.h"
#include "define.h"

// 构造函数
Hero::Hero(int tankRow, int tankColumn, int tankDirection) : Tank(TANK_OWNER_HERO, tankRow, tankColumn, tankDirection) {}

敌方坦克类

Enemy.h

#pragma once
#include "Tank.h"

// 敌方坦克类
class Enemy : public Tank
{
public:
	int target = HOME;		// 坦克射击的目标(我方坦克,老巢)

public:

	// 构造函数
	Enemy(int tankRow, int tankColumn, int tankDirection);

};

Enemy.cpp

#include "Enemy.h"

// 构造函数
Enemy::Enemy(int tankRow, int tankColumn, int tankDirection) : Tank::Tank(TANK_OWNER_ENEMY, tankRow, tankColumn, tankDirection){}

main.cpp

#include "lag.h"
#include "define.h"
#include "GameMap.h"
#include "Block.h"
#include "Hero.h"
#include "Enemy.h"
#include "Bullet.h"
#include "Bomb.h"
#include "Star.h"

// 项目结构
struct _stu_project
{
	int gameStatus = GAME_STATUS_RUN;					// 游戏状态
	bool refreshFlag = false;							// 刷新标识
	int level = 0;										// 游戏关卡
	int enemyMaxNum = 0;								// 敌方坦克最大数量
	int enemyCreateNum = 0;								// 敌方坦克投放数量
	int enemyDeadNum = 0;								// 敌方坦克死亡数量
	int enemyArmorDeadNum[4] = {0,0,0,0};				// 敌方不同装甲坦克死亡数量
	IMAGE imgLogo;										// Logo图片
	IMAGE imgLevel;										// 关卡图片
	IMAGE imgScore;										// 分数图片
	IMAGE imgSuccess;									// 游戏成功图片
	IMAGE imgFailure;									// 游戏失败图片
	int(*map)[26] = nullptr;							// 关卡地图

} stu_project;

// 子弹所在行列结构
struct _stu_bullet_pos
{
	int row1;
	int col1;
	int row2;
	int col2;
};

// 方块类
Block block;

// 我方坦克类
Hero hero(24, 8, TANK_DIRECTION_UP);

// 我方子弹池
vector<Bullet>& heroBulletPool = hero.getBulletPool();

// 敌方坦克类
vector<Enemy> enemyPool;

// 爆炸池
vector<Bomb> bombPool;

// 星星池
vector<Star> starPool;

// 函数声明
void createWindow();
void welcome();
void loadResources();
void initGame();
void paint();
void run();
void keyEvent();
void mouseEvent();
void starCreate();
void starAdd(int row, int column);
void enemyTankCreate(int row, int column);
void enemyTankMove();
void enemyTankShoot();
int enemyTankAI(Enemy& enemy);
void bombAdd(int x, int y);
void collide();
void doGame();
void newGame();
void showScore();
void getBulletPos(struct _stu_bullet_pos* pos, int x, int y, int direction);

// 坦克大战
int main()
{
	// 创建窗口
	createWindow();

	// 显示封面
	welcome();

	// 开始游戏
	newGame();

	// 暂停一下
	system("pause");

	// 关闭窗口
	closegraph();

	return 0;
}

// 创建窗口
void createWindow()
{
	// 创建并得到窗口句柄
	HWND hWnd = initgraph(WIN_WIDTH, WIN_HEIGHT);

	// 修改标题
	SetWindowText(hWnd, TITLE);

	// 居中显示
	myCenterWindow(hWnd);
}

// 加载资源
void loadResources()
{
	// 加载游戏成功图片
	loadimage(&stu_project.imgSuccess, "./resources/image/success.png");

	// 加载游戏失败图片
	loadimage(&stu_project.imgFailure, "./resources/image/failure.png");

	// 加载关卡图片
	loadimage(&stu_project.imgLevel, "./resources/image/level.png");

	// 加载Logo图片
	loadimage(&stu_project.imgLogo, "./resources/image/logo.png");

	// 加载分数图片
	loadimage(&stu_project.imgScore, "./resources/image/score.jpg");
}

// 显示封面
void welcome()
{
	// 显示封面
	IMAGE imgWelcome;
	loadimage(&imgWelcome, "./resources/image/welcome.gif");
	putimage(0, 0, &imgWelcome);

	// 加载资源
	loadResources();

	// 暂停一下
	system("pause");
}

// 初始化游戏
void initGame()
{
	// 项目参数初始化
	stu_project.gameStatus = GAME_STATUS_RUN;
	stu_project.refreshFlag = false;
	stu_project.enemyMaxNum = GameMap::getEnemyTankNum(stu_project.level);
	stu_project.enemyCreateNum = 0;
	stu_project.enemyDeadNum = 0;
	stu_project.map = GameMap::getMap();
	for (int i = 0; i < 4; i++){stu_project.enemyArmorDeadNum[i] = 0;}

	// 设置游戏关卡
	GameMap::setLevel(stu_project.level);

	// 我方坦克初始化
	hero.reset();
	hero.status = TANK_STATUS_RUN;
	hero.toMap();

	// 敌方坦克池初始化10辆坦克
	int lenEnemyPool = enemyPool.size();
	if (lenEnemyPool == 0)
	{
		for (int i = 0; i < 10; i++)
		{
			Enemy enemy(0,0,TANK_DIRECTION_DOWN);
			enemyPool.push_back(enemy);
		}
	}
	else
	{
		for (int i = 0; i < lenEnemyPool; i++)
		{
			enemyPool[i].reset();
			vector<Bullet>& enemyBulletPool = enemyPool[i].getBulletPool();
			int lenEnemyBulletPool = enemyBulletPool.size();
			for (int j = 0; j < lenEnemyBulletPool; j++) { enemyBulletPool[j].status = BULLET_STATUS_FREE; }
		}
	}

	// 星星初始化
	int lenStarPool = starPool.size();
	if (lenStarPool == 0)
	{
		for (int i = 0; i < 3; i++)
		{
			Star star;
			starPool.push_back(star);
		}
	}
	else
	{
		for (int i = 0; i < lenStarPool; i++) { starPool[i].status = STAR_STATUS_FREE; }
	}

	// 爆炸初始化
	int lenBombPool = bombPool.size();
	for (int i = 0; i < lenBombPool; i++) {	bombPool[i].status = BOMB_STATUS_FREE;}

}

// 绘制窗口
void paint()
{
	// 开启双缓冲机制,防止闪烁
	BeginBatchDraw();

	// 绘制游戏区域
	setcolor(BLACK);
	cleardevice();
	setfillcolor(LIGHTGRAY);
	fillrectangle(GAME_WIDTH, -2, WIN_WIDTH, WIN_HEIGHT + 2);

	// 绘制分数
	settextstyle(20, 0, "微软雅黑");
	settextcolor(YELLOW);
	setbkmode(TRANSPARENT);
	myDrawString(GAME_WIDTH + 20, 6, "总数:" + to_string(stu_project.enemyMaxNum));
	myDrawString(GAME_WIDTH + 20, 26, "死亡:" + to_string(stu_project.enemyDeadNum));
	myDrawString(GAME_WIDTH + 20, 46, "剩余:" + to_string(stu_project.enemyMaxNum - stu_project.enemyDeadNum));
	int notCreateNum = stu_project.enemyMaxNum - stu_project.enemyCreateNum;
	if (notCreateNum > 0)
	{
		int logoRow = notCreateNum / 2;
		if (notCreateNum % 2 != 0) { logoRow++; }
		int logoCount = 0;
		for (int i = 0; i < logoRow; i++)
		{
			for (int j = 0; j < 2; j++)
			{
				if (logoCount >= notCreateNum) { break; }
				myDrawImage(GAME_WIDTH + 22 + j * (20 + 14), 80 + i * (16 + 4), &stu_project.imgLogo,WIN_WIDTH,WIN_HEIGHT);
				logoCount++;
			}
		}
	}
	myDrawImage(GAME_WIDTH + 20, 330, &stu_project.imgLevel);
	settextcolor(RED);
	myDrawString(GAME_WIDTH + 20, 380, "关数:" + to_string(stu_project.level + 1));
	settextcolor(WHITE);
	myDrawString(GAME_WIDTH + 20, 420, "作者:Lag");

	// 绘制地图
	block.draw();

	// 绘制我方坦克
	hero.draw();

	// 绘制我方子弹
	int lenHeroBulletPool = heroBulletPool.size();
	for (int i = 0; i < lenHeroBulletPool; i++)
	{
		if (heroBulletPool[i].status == BULLET_STATUS_RUN)
		{
			heroBulletPool[i].draw();
		}
	}

	// 绘制敌方坦克、子弹
	int lenEnemyPool = enemyPool.size();
	for (int i = 0; i < lenEnemyPool; i++)
	{
		if (enemyPool[i].status == TANK_STATUS_RUN) { enemyPool[i].draw(); }
		vector<Bullet>& enemyBulletPool = enemyPool[i].getBulletPool();
		int lenEnemyBulletPool = enemyBulletPool.size();
		for (int j = 0; j < lenEnemyBulletPool; j++)
		{
			if (enemyBulletPool[j].status == BULLET_STATUS_RUN){enemyBulletPool[j].draw();}
		}
	}
	
	// 绘制爆炸
	int lenBombPool = bombPool.size();
	for (int i = 0; i < lenBombPool; i++)
	{
		if (bombPool[i].status == BOMB_STATUS_RUN)
		{
			bombPool[i].draw();
		}
	}

	// 绘制星星
	int lenStarPool = starPool.size();
	for (int i = 0; i < lenStarPool; i++)
	{
		if (starPool[i].status == STAR_STATUS_RUN)
		{
			starPool[i].draw();
		}
	}

	// 结束双缓冲机制
	EndBatchDraw();
}

// 向星星池增加
void starAdd(int row, int column)
{
	// 流星雨
	myPlayAudio("./resources/audio/star.mp3");

	// 查找空闲的星星
	int len = starPool.size();
	for (int i = 0; i < len; i++)
	{
		if (starPool[i].status == STAR_STATUS_FREE)
		{
			starPool[i].row = row;
			starPool[i].column = column;
			starPool[i].frameIndex = 0;
			starPool[i].status = STAR_STATUS_RUN;
			break;
		}
	}
}

// 星星创建(在坦克创建前先创建星星)
void starCreate()
{
	// 创建坦克标识
	bool createFlag = false;

	if (stu_project.enemyCreateNum == 0 || myTimer(INTERVAL_CREATEENEMY, TIMERID_CREATEENEMY)) { createFlag = true; }

	if (createFlag)
	{
		// 判断投放地点是否为空
		int createPos[3] = { -1,-1,-1 };
		int createPosNum = 0;
		if (stu_project.map[0][0] == BLANK && stu_project.map[0][1] == BLANK && stu_project.map[1][0] == BLANK && stu_project.map[1][1] == BLANK)			// 判断左上角位置是否可以投放
		{
			createPos[createPosNum] = 0;
			createPosNum++;
		}
		if (stu_project.map[0][12] == BLANK && stu_project.map[0][13] == BLANK && stu_project.map[1][12] == BLANK && stu_project.map[1][13] == BLANK)		// 判断中间位置是否可以投放
		{
			createPos[createPosNum] = 12;
			createPosNum++;
		}
		if (stu_project.map[0][24] == BLANK && stu_project.map[0][25] == BLANK && stu_project.map[1][24] == BLANK && stu_project.map[1][25] == BLANK)		// 判断右上角位置是否可以投放
		{
			createPos[createPosNum] = 24;
			createPosNum++;
		}
		if (createPosNum < 1) { return; }		// 无投放位置,退出

		// 首次一次性投放3辆坦克
		if (stu_project.enemyCreateNum == 0)
		{
			for (int i = 0; i < createPosNum; i++)
			{
				// 先把茅坑占上
				stu_project.map[0][createPos[i]] = 999;
				stu_project.map[0][createPos[i] + 1] = 999;
				stu_project.map[1][createPos[i]] = 999;
				stu_project.map[1][createPos[i] + 1] = 999;
				// 增加星星
				starAdd(0, createPos[i]);
			}
		}
		else     // 每隔一段时间投放一辆坦克
		{
			// 判断是否达到最大投放数量
			if (stu_project.enemyCreateNum >= stu_project.enemyMaxNum) { return; }
			// 得到随机投放位置
			int pos = createPos[myRandom(0, createPosNum - 1)];
			// 先把茅坑占上
			stu_project.map[0][pos] = 999;
			stu_project.map[0][pos + 1] = 999;
			stu_project.map[1][pos] = 999;
			stu_project.map[1][pos + 1] = 999;
			// 增加星星
			starAdd(0, pos);
		}
	}
}

// 敌方坦克创建(在星星创建的位置)
void enemyTankCreate(int row,int column)
{
	// 在坦克池中寻找空闲的坦克
	Enemy* enemy = nullptr;
	int lenEnemyPool = enemyPool.size();
	for (int i = 0; i < lenEnemyPool; i++)
	{
		if (enemyPool[i].status == TANK_STATUS_FREE)
		{
			enemy = &enemyPool[i];
			break;
		}
	}
	if (enemy == nullptr)			// 没有就增加一个
	{
		Enemy newEnemy(0, 0, TANK_DIRECTION_DOWN);
		enemyPool.push_back(newEnemy);
		enemy = &enemyPool[lenEnemyPool];
	}

	// 开始投放
	enemy->row = row;
	enemy->oldRow = enemy->row;
	enemy->column = column;
	enemy->oldColumn = enemy->column;
	enemy->x = enemy->column * BLOCK_SIZE;
	enemy->y = 0;
	enemy->direction = TANK_DIRECTION_DOWN;
	if (stu_project.enemyCreateNum >= 3)
	{
		enemy->armor = myRandom(0, 3);
	}
	else
	{
		enemy->armor = 0;
	}
	enemy->originalArmor = enemy->armor;
	enemy->target = myRandom(TANK_OWNER_HERO, HOME);
	enemy->status = TANK_STATUS_RUN;
	enemy->toMap();
	stu_project.enemyCreateNum++;

}

// 敌方坦克AI(返回方向)
// 原理:判断目标与敌方坦克的相应位置,找出哪个方向最可能靠近目标。
int enemyTankAI(Enemy &enemy)
{
	// 先剔除墙与铁块那个方向(铁块暂时打不动)
	int validDirectory[4][2] = { -1,-1,-1,-1,-1,-1,-1,-1 };		// 可用方向数组[方向][空地/墙]
	int validDirectoryNum = 0;
	for (int i = 0; i < 4; i++)
	{
		bool blankFlag = false;		// 空地标识(true-是空地,false-非空地)
		if (i == TANK_DIRECTION_UP)
		{
			if (enemy.row == 0){continue;}
			if (stu_project.map[enemy.row - 1][enemy.column] == IRON || stu_project.map[enemy.row - 1][enemy.column + 1] == IRON) { continue; }
			if (stu_project.map[enemy.row - 1][enemy.column] == BLANK && stu_project.map[enemy.row - 1][enemy.column + 1] == BLANK) { blankFlag = true; }
		}
		else if (i == TANK_DIRECTION_DOWN)
		{
			if (enemy.row == 24) { continue; }
			if (stu_project.map[enemy.row + 2][enemy.column] == IRON || stu_project.map[enemy.row + 2][enemy.column + 1] == IRON) { continue; }
			if (stu_project.map[enemy.row + 2][enemy.column] == BLANK && stu_project.map[enemy.row + 2][enemy.column + 1] == BLANK) { blankFlag = true; }
		}
		else if (i == TANK_DIRECTION_LEFT)
		{
			if (enemy.column == 0) { continue; }
			if (stu_project.map[enemy.row][enemy.column - 1] == IRON || stu_project.map[enemy.row + 1][enemy.column - 1] == IRON) { continue; }
			if (stu_project.map[enemy.row][enemy.column - 1] == BLANK && stu_project.map[enemy.row + 1][enemy.column - 1] == BLANK) { blankFlag = true; }
		}
		else if (i == TANK_DIRECTION_RIGHT)
		{
			if (enemy.column == 24) { continue; }
			if (stu_project.map[enemy.row][enemy.column + 2] == IRON || stu_project.map[enemy.row + 1][enemy.column + 2] == IRON) { continue; }
			if (stu_project.map[enemy.row][enemy.column + 2] == BLANK && stu_project.map[enemy.row + 1][enemy.column + 2] == BLANK) { blankFlag = true; }
		}
		validDirectory[validDirectoryNum][0] = i;
		if (blankFlag)
		{
			validDirectory[validDirectoryNum][1] = BLANK;
		}
		else
		{
			validDirectory[validDirectoryNum][1] = WALL;
		}
		validDirectoryNum++;
	}

	// 判断目标与敌方坦克位置关系
	int directory[4] = { -1,-1,-1,-1 };
	int targetRow;
	int targetColumn;
	if (enemy.target == TANK_OWNER_HERO)	// 目标是我方坦克
	{
		targetRow = hero.row;
		targetColumn = hero.column;
	}
	else   // 目标是老巢
	{
		targetRow = 24;
		targetColumn = 12;
	}
	if (targetColumn > enemy.column)		// 目标在敌方坦克右边
	{
		if (targetRow < enemy.row)			// 右上角(上或右)
		{
			for (int i = 0; i < validDirectoryNum; i++)
			{
				if (validDirectory[i][0] == TANK_DIRECTION_UP || validDirectory[i][0] == TANK_DIRECTION_RIGHT)
				{
					// 空地优先级别高
					if (validDirectory[i][1] == BLANK)
					{
						if (directory[0] != -1){directory[1] = directory[0];}
						directory[0] = validDirectory[i][0];
						continue;
					}
					// 从左向右填充
					for (int j = 0; j < 4; j++)
					{
						if (directory[j] == -1)
						{
							directory[j] = validDirectory[i][0];
							break;
						}
					}
				}
				else
				{
					// 从右向左填充
					for (int j = 3; j >= 0; j--)
					{
						if (directory[j] == -1)
						{
							directory[j] = validDirectory[i][0];
							break;
						}
					}
				}
			}
		}
		else     // 右下角(下或右)
		{
			for (int i = 0; i < validDirectoryNum; i++)
			{
				if (validDirectory[i][0] == TANK_DIRECTION_DOWN || validDirectory[i][0] == TANK_DIRECTION_RIGHT)
				{
					// 空地优先级别高
					if (validDirectory[i][1] == BLANK)
					{
						if (directory[0] != -1) { directory[1] = directory[0]; }
						directory[0] = validDirectory[i][0];
						continue;
					}
					// 从左向右填充
					for (int j = 0; j < 4; j++)
					{
						if (directory[j] == -1)
						{
							directory[j] = validDirectory[i][0];
							break;
						}
					}
				}
				else
				{
					// 从右向左填充
					for (int j = 3; j >= 0; j--)
					{
						if (directory[j] == -1)
						{
							directory[j] = validDirectory[i][0];
							break;
						}
					}
				}
			}
		}
		// 特殊情况(同一条线上)
		if (targetRow == enemy.row)
		{
			for (int i = 0; i < validDirectoryNum; i++)
			{
				if (validDirectory[i][0] == TANK_DIRECTION_RIGHT)
				{
					if (validDirectory[i][1] == BLANK){return validDirectory[i][0];}		// 是空地就必须勇敢的冲过去
				}
			}
		}
	}
	else									// 目标在敌方坦克左边
	{
		if (targetRow < enemy.row)			// 左上角(上或左)
		{
			for (int i = 0; i < validDirectoryNum; i++)
			{
				if (validDirectory[i][0] == TANK_DIRECTION_UP || validDirectory[i][0] == TANK_DIRECTION_LEFT)
				{
					// 空地优先级别高
					if (validDirectory[i][1] == BLANK)
					{
						if (directory[0] != -1) { directory[1] = directory[0]; }
						directory[0] = validDirectory[i][0];
						continue;
					}
					// 从左向右填充
					for (int j = 0; j < 4; j++)
					{
						if (directory[j] == -1)
						{
							directory[j] = validDirectory[i][0];
							break;
						}
					}
				}
				else
				{
					// 从右向左填充
					for (int j = 3; j >= 0; j--)
					{
						if (directory[j] == -1)
						{
							directory[j] = validDirectory[i][0];
							break;
						}
					}
				}
			}
		}
		else     // 左下角(下或左)
		{
			for (int i = 0; i < validDirectoryNum; i++)
			{
				if (validDirectory[i][0] == TANK_DIRECTION_DOWN || validDirectory[i][0] == TANK_DIRECTION_LEFT)
				{
					// 空地优先级别高
					if (validDirectory[i][1] == BLANK)
					{
						if (directory[0] != -1) { directory[1] = directory[0]; }
						directory[0] = validDirectory[i][0];
						continue;
					}
					// 从左向右填充
					for (int j = 0; j < 4; j++)
					{
						if (directory[j] == -1)
						{
							directory[j] = validDirectory[i][0];
							break;
						}
					}
				}
				else
				{
					// 从右向左填充
					for (int j = 3; j >= 0; j--)
					{
						if (directory[j] == -1)
						{
							directory[j] = validDirectory[i][0];
							break;
						}
					}
				}
			}
		}
		// 特殊情况(同一条线上)
		if (targetRow == enemy.row)
		{
			for (int i = 0; i < validDirectoryNum; i++)
			{
				if (validDirectory[i][0] == TANK_DIRECTION_LEFT)
				{
					if (validDirectory[i][1] == BLANK) { return validDirectory[i][0]; }		// 是空地就必须勇敢的冲过去
				}
			}
		}
	}
	
	if (targetColumn == enemy.column)	// 目标在敌方坦克正上或下方
	{
		// 特殊情况(同一条线上)
		if (targetRow < enemy.row)		// 正上方
		{
			for (int i = 0; i < validDirectoryNum; i++)
			{
				if (validDirectory[i][0] == TANK_DIRECTION_UP)
				{
					if (validDirectory[i][1] == BLANK) { return validDirectory[i][0]; }		// 是空地就必须勇敢的冲过去
				}
			}
		}
		else
		{
			for (int i = 0; i < validDirectoryNum; i++)
			{
				if (validDirectory[i][0] == TANK_DIRECTION_DOWN)
				{
					if (validDirectory[i][1] == BLANK) {return validDirectory[i][0]; }		// 是空地就必须勇敢的冲过去
				}
			}
		}
	}

	// 方向补全
	for (int i = 0; i < 4; i++)
	{
		if (directory[i] == -1) { directory[i] = enemy.direction; }
	}

	// 随机抽取4:3:2:1
	int random = myRandom(1,10);
	if (random <= 4)
	{
		return directory[0];
	}
	else if (random <= 7)
	{
		return directory[1];
	}
	else if (random <= 9)
	{
		return directory[2];
	}
	else
	{
		return directory[3];
	}

}

// 敌方坦克移动
void enemyTankMove()
{
	if (myTimer(INTERVAL_MOVEENEMY, TIMERID_MOVEENEMY))
	{
		int lenEnemyPool = enemyPool.size();
		for (int i = 0; i < lenEnemyPool; i++)
		{
			if (enemyPool[i].status == TANK_STATUS_RUN)
			{
				// 得到移动方向
				enemyPool[i].direction = enemyTankAI(enemyPool[i]);
				enemyPool[i].move(enemyPool[i].direction);
				stu_project.refreshFlag = true;
			}
		}
	}
}

// 敌方坦克射击
void enemyTankShoot()
{
	if (myTimer(INTERVAL_BULLET_SHOOT, TIMERID_BULLET_SHOOT))
	{
		int lenEnemyPool = enemyPool.size();
		for (int i = 0; i < lenEnemyPool; i++)
		{
			if (enemyPool[i].status == TANK_STATUS_RUN)
			{
				// 敌方坦克比较傻,不爱射击
				if (myRandom(1, 10) < 4){enemyPool[i].shoot();}			// 30%几率开枪
				stu_project.refreshFlag = true;
			}
		}
	}
}

// 向爆炸池增加
void bombAdd(int x, int y)
{
	// 查找空闲的爆炸
	Bomb* bomb = nullptr;
	int len = bombPool.size();
	for (int i = 0; i < len; i++)
	{
		if (bombPool[i].status == BOMB_STATUS_FREE)
		{
			bomb = &bombPool[i];
			break;
		}
	}
	if (bomb == nullptr)				// 没有就增加一个
	{
		Bomb newBomb;
		bombPool.push_back(newBomb);
		bomb = &bombPool[len];
	}
	bomb->x = x;
	bomb->y = y;
	bomb->frameIndex = 0;
	bomb->status = BOMB_STATUS_RUN;
}

// 得到子弹所在行列位置(子弹位于坦克中间位置,所以正对着2个格子的中间位置,所以计算时2个格子都在其射击范围内)
void getBulletPos(struct _stu_bullet_pos* pBulletPos, int x, int y, int direction)
{
	int x1, y1, x2, y2;

	// 重算子弹图片中心点坐标(因为此时的x与y是子弹图片左上角的坐标)
	x = x + BULLET_SIZE / 2;
	y = y + BULLET_SIZE / 2;

	// 根据方向判断2个格子位置
	if (direction == TANK_DIRECTION_UP || direction == TANK_DIRECTION_DOWN)
	{
		x1 = x - BLOCK_SIZE / 2;
		y1 = y;
		x2 = x + BLOCK_SIZE / 2;
		y2 = y;
	}
	else
	{
		x1 = x;
		y1 = y - BLOCK_SIZE / 2;
		x2 = x;
		y2 = y + BLOCK_SIZE / 2;
	}
	pBulletPos->row1 = y1 / BLOCK_SIZE;
	pBulletPos->col1 = x1 / BLOCK_SIZE;
	pBulletPos->row2 = y2 / BLOCK_SIZE;
	pBulletPos->col2 = x2 / BLOCK_SIZE;
}

// 碰撞处理
void collide()
{
	// 子弹所在位置结构体
	struct _stu_bullet_pos stu_bullet_pos;

	// 判断我方子弹是否与敌方坦克或块或老巢碰撞
	int lenHeroBulletPool = heroBulletPool.size();
	for (int i = 0; i < lenHeroBulletPool; i++)
	{
		if (heroBulletPool[i].status == BULLET_STATUS_RUN)
		{
			// 得到子弹所在行与列
			getBulletPos(&stu_bullet_pos, heroBulletPool[i].x, heroBulletPool[i].y, heroBulletPool[i].direction);
			// 得到子弹2个点的值
			int v1 = stu_project.map[stu_bullet_pos.row1][stu_bullet_pos.col1];
			int v2 = stu_project.map[stu_bullet_pos.row2][stu_bullet_pos.col2];
			if (v1 == 0 && v2 == 0) { continue; }
			if (v1 == TANK_OWNER_HERO && v2 == TANK_OWNER_HERO) { continue; }
			// 判断是否与墙块碰撞
			if (v1 == WALL) { stu_project.map[stu_bullet_pos.row1][stu_bullet_pos.col1] = 0; }
			if (v2 == WALL) { stu_project.map[stu_bullet_pos.row2][stu_bullet_pos.col2] = 0; }
			// 判断是否与老巢碰撞
			if (v1 == HOME || v2 == HOME) { stu_project.gameStatus = GAME_STATUS_OVER; }
			// 判断是否与敌方坦克碰撞
			int lenEnemyPool = enemyPool.size();
			for (int i = 0; i < lenEnemyPool; i++)
			{
				if (enemyPool[i].status == TANK_STATUS_RUN) 
				{
					if (
							(enemyPool[i].row == stu_bullet_pos.row1 && enemyPool[i].column == stu_bullet_pos.col1) || 
							(enemyPool[i].row == stu_bullet_pos.row1 && enemyPool[i].column + 1 == stu_bullet_pos.col1) || 
							(enemyPool[i].row + 1 == stu_bullet_pos.row1 && enemyPool[i].column == stu_bullet_pos.col1) ||
							(enemyPool[i].row + 1 == stu_bullet_pos.row1 && enemyPool[i].column + 1 == stu_bullet_pos.col1) ||
							(enemyPool[i].row == stu_bullet_pos.row2 && enemyPool[i].column == stu_bullet_pos.col2) ||
							(enemyPool[i].row == stu_bullet_pos.row2 && enemyPool[i].column + 1 == stu_bullet_pos.col2) ||
							(enemyPool[i].row + 1 == stu_bullet_pos.row2 && enemyPool[i].column == stu_bullet_pos.col2) ||
							(enemyPool[i].row + 1 == stu_bullet_pos.row2 && enemyPool[i].column + 1 == stu_bullet_pos.col2)
						)
					{
						myPlayAudio("./resources/audio/boom.wav");
						if (enemyPool[i].armor == 0)
						{
							enemyPool[i].reset();
							stu_project.enemyDeadNum++;
							stu_project.enemyArmorDeadNum[enemyPool[i].originalArmor]++;
							if (stu_project.enemyDeadNum >= stu_project.enemyMaxNum){stu_project.gameStatus = GAME_STATUS_WIN;}
							break;
						}
						else
						{
							enemyPool[i].armor--;
						}
					}
				}
			}
			// 子弹销毁
			heroBulletPool[i].status = BULLET_STATUS_FREE;
			// 子弹爆炸
			bombAdd(heroBulletPool[i].x, heroBulletPool[i].y);
		}
	}

	// 判断敌方子弹是否与我方坦克或块或老巢碰撞(不需要判断敌方坦克状态,因为即使坦克销毁子弹可能仍然在飞)
	int lenEnemyPool = enemyPool.size();
	for (int m = 0; m < lenEnemyPool; m++)
	{
		vector<Bullet>& enemyBulletPool = enemyPool[m].getBulletPool();
		int lenEnemyBulletPool = enemyBulletPool.size();
		for (int i = 0; i < lenEnemyBulletPool; i++)
		{
			if (enemyBulletPool[i].status == BULLET_STATUS_RUN)
			{
				// 得到子弹所在行与列
				getBulletPos(&stu_bullet_pos, enemyBulletPool[i].x, enemyBulletPool[i].y, enemyBulletPool[i].direction);
				// 得到子弹2个点的值
				int v1 = stu_project.map[stu_bullet_pos.row1][stu_bullet_pos.col1];
				int v2 = stu_project.map[stu_bullet_pos.row2][stu_bullet_pos.col2];
				if (v1 == 0 && v2 == 0) { continue; }
				if (v1 == TANK_OWNER_ENEMY && v2 == TANK_OWNER_ENEMY) { continue; }
				// 判断是否与墙块碰撞
				if (v1 == WALL) { stu_project.map[stu_bullet_pos.row1][stu_bullet_pos.col1] = 0; }
				if (v2 == WALL) { stu_project.map[stu_bullet_pos.row2][stu_bullet_pos.col2] = 0; }
				// 判断是否与老巢碰撞
				if (v1 == HOME || v2 == HOME) { stu_project.gameStatus = GAME_STATUS_OVER; }
				// 判断是否与我方坦克碰撞
				if (hero.status == TANK_STATUS_RUN)
				{
					if (
							(hero.row == stu_bullet_pos.row1 && hero.column == stu_bullet_pos.col1) ||
							(hero.row == stu_bullet_pos.row1 && hero.column + 1 == stu_bullet_pos.col1) ||
							(hero.row + 1 == stu_bullet_pos.row1 && hero.column == stu_bullet_pos.col1) ||
							(hero.row + 1 == stu_bullet_pos.row1 && hero.column + 1 == stu_bullet_pos.col1) ||
							(hero.row == stu_bullet_pos.row2 && hero.column == stu_bullet_pos.col2) ||
							(hero.row == stu_bullet_pos.row2 && hero.column + 1 == stu_bullet_pos.col2) ||
							(hero.row + 1 == stu_bullet_pos.row2 && hero.column == stu_bullet_pos.col2) ||
							(hero.row + 1 == stu_bullet_pos.row2 && hero.column + 1 == stu_bullet_pos.col2)
						)
					{
						if (hero.armor == 0)
						{
							hero.reset();
							stu_project.gameStatus = GAME_STATUS_OVER;
						}
						else
						{
							hero.armor--;
						}
					}
				}
				// 子弹销毁
				enemyBulletPool[i].status = BULLET_STATUS_FREE;
				// 子弹爆炸
				bombAdd(enemyBulletPool[i].x, enemyBulletPool[i].y);
			}
		}
	}

}

// 游戏进程
void run()
{
	// 重置刷新标识
	stu_project.refreshFlag = false;

	// 星星创建
	starCreate();

	// 星星进程
	if (myTimer(INTERVAL_STAR, TIMERID_STAR))
	{
		int len = starPool.size();
		for (int i = 0; i < len; i++)
		{
			if (starPool[i].status == STAR_STATUS_RUN)
			{
				int index = starPool[i].frameIndex;
				if (index >= starPool[i].maxFrame - 1)
				{
					starPool[i].status = STAR_STATUS_FREE;
					enemyTankCreate(starPool[i].row, starPool[i].column);		// 创建敌方坦克
					continue;
				}
				starPool[i].frameIndex = ++index;
			}
		}
	}

	// 敌方坦克移动
	enemyTankMove();

	// 敌方坦克射击
	enemyTankShoot();

	// 坦克移动进程
	if (myTimer(INTERVAL_TANKMOVE, TIMERID_TANKMOVE))
	{
		// 我方坦克移动
		if (hero.oldRow != hero.row)
		{
			int destY = hero.row * BLOCK_SIZE;
			if (hero.direction == TANK_DIRECTION_UP)
			{
				if (hero.y > destY)
				{
					hero.y = hero.y - hero.speed;
					hero.track = !hero.track;		// 切换履带
				}
				else
				{
					hero.oldRow = hero.row;
					hero.y = destY;					// 坐标微调
				}
			}
			else if (hero.direction == TANK_DIRECTION_DOWN)
			{
				if (hero.y < destY)
				{
					hero.y = hero.y + hero.speed;
					hero.track = !hero.track;
				}
				else
				{
					hero.oldRow = hero.row;
					hero.y = destY;
				}
			}
			stu_project.refreshFlag = true;
		}
		else if (hero.column != hero.oldColumn)
		{
			int destX = hero.column * BLOCK_SIZE;
			if (hero.direction == TANK_DIRECTION_LEFT)
			{
				if (hero.x > destX)
				{
					hero.x = hero.x - hero.speed;
					hero.track = !hero.track;
				}
				else
				{
					hero.oldColumn = hero.column;
					hero.x = destX;
				}
			}
			else if (hero.direction == TANK_DIRECTION_RIGHT)
			{
				if (hero.x < destX)
				{
					hero.x = hero.x + hero.speed;
					hero.track = !hero.track;
				}
				else
				{
					hero.oldColumn = hero.column;
					hero.x = destX;
				}
			}
			stu_project.refreshFlag = true;
		}
		// 敌方坦克移动
		int lenEnemyPool = enemyPool.size();
		for (int i = 0; i < lenEnemyPool; i++)
		{
			if (enemyPool[i].status == TANK_STATUS_RUN)
			{
				if (enemyPool[i].oldRow != enemyPool[i].row)
				{
					int destY = enemyPool[i].row * BLOCK_SIZE;
					if (enemyPool[i].direction == TANK_DIRECTION_UP)
					{
						if (enemyPool[i].y > destY)
						{
							enemyPool[i].y = enemyPool[i].y - enemyPool[i].speed;
							enemyPool[i].track = !enemyPool[i].track;		// 切换履带
						}
						else
						{
							enemyPool[i].oldRow = enemyPool[i].row;
							enemyPool[i].y = destY;					// 坐标微调
						}
					}
					else if (enemyPool[i].direction == TANK_DIRECTION_DOWN)
					{
						if (enemyPool[i].y < destY)
						{
							enemyPool[i].y = enemyPool[i].y + enemyPool[i].speed;
							enemyPool[i].track = !enemyPool[i].track;
						}
						else
						{
							enemyPool[i].oldRow = enemyPool[i].row;
							enemyPool[i].y = destY;
						}
					}
					stu_project.refreshFlag = true;
				}
				else if (enemyPool[i].column != enemyPool[i].oldColumn)
				{
					int destX = enemyPool[i].column * BLOCK_SIZE;
					if (enemyPool[i].direction == TANK_DIRECTION_LEFT)
					{
						if (enemyPool[i].x > destX)
						{
							enemyPool[i].x = enemyPool[i].x - enemyPool[i].speed;
							enemyPool[i].track = !enemyPool[i].track;
						}
						else
						{
							enemyPool[i].oldColumn = enemyPool[i].column;
							enemyPool[i].x = destX;
						}
					}
					else if (enemyPool[i].direction == TANK_DIRECTION_RIGHT)
					{
						if (enemyPool[i].x < destX)
						{
							enemyPool[i].x = enemyPool[i].x + enemyPool[i].speed;
							enemyPool[i].track = !enemyPool[i].track;
						}
						else
						{
							enemyPool[i].oldColumn = enemyPool[i].column;
							enemyPool[i].x = destX;
						}
					}
					stu_project.refreshFlag = true;
				}
			}
		}
	}

	// 子弹进程
	if (myTimer(INTERVAL_BULLET_RUN, TIMERID_BULLET_RUN))
	{
		// 我方子弹运行
		int lenHeroBulletPool = heroBulletPool.size();
		for (int i = 0; i < lenHeroBulletPool; i++)
		{
			if (heroBulletPool[i].status == BULLET_STATUS_RUN)
			{
				heroBulletPool[i].run();
			}
		}
		// 敌方子弹运行
		int lenEnemyPool = enemyPool.size();
		for (int i = 0; i < lenEnemyPool; i++)
		{
			vector<Bullet>& enemyBulletPool = enemyPool[i].getBulletPool();
			int lenEnemyBulletPool = enemyBulletPool.size();
			for (int j = 0; j < lenEnemyBulletPool; j++)
			{
				if (enemyBulletPool[j].status == BULLET_STATUS_RUN)
				{
					enemyBulletPool[j].run();
				}
			}
		}
	}

	// 碰撞处理
	collide();

	// 爆炸进程
	if (myTimer(INTERVAL_BOMB, TIMERID_BOMB))
	{
		int len = bombPool.size();
		for (int i = 0; i < len; i++)
		{
			if (bombPool[i].status == BOMB_STATUS_RUN)
			{
				int index = bombPool[i].frameIndex;
				if (index >= bombPool[i].maxFrame - 1)
				{
					bombPool[i].status = BOMB_STATUS_FREE;
					break;
				}
				bombPool[i].frameIndex = ++index;
			}
		}
	}

	// 刷新界面
	if (stu_project.refreshFlag) { paint(); }

}

// 键盘监控
void keyEvent()
{
	// 重置刷新标识
	stu_project.refreshFlag = false;

	// 方向键只运行同时按一个,用else if判断
	if (myKeyDown(VK_UP))				// 上键
	{
		if (hero.move(TANK_DIRECTION_UP)) { stu_project.refreshFlag = true; }
	}
	else if (myKeyDown(VK_DOWN))		// 下键
	{
		if (hero.move(TANK_DIRECTION_DOWN)) { stu_project.refreshFlag = true; }
	}
	else if (myKeyDown(VK_LEFT))		// 左键
	{
		if (hero.move(TANK_DIRECTION_LEFT)) { stu_project.refreshFlag = true; }
	}
	else if (myKeyDown(VK_RIGHT))		// 右键
	{
		if (hero.move(TANK_DIRECTION_RIGHT)) { stu_project.refreshFlag = true; }
	}

	// 其他键不受限制
	if (myKeyDown(VK_SPACE))			// 空格
	{
		hero.shoot();
		stu_project.refreshFlag = true;
	}

	// 刷新界面
	if (stu_project.refreshFlag) { paint(); }
}

// 鼠标监控
void mouseEvent()
{
	ExMessage msg;							// 鼠标消息结构体
	if (peekmessage(&msg, EM_MOUSE))		// 只监听鼠标消息
	{
		switch (msg.message)
		{
		case WM_LBUTTONUP:				// 鼠标左键释放(用msg.x与msg.y来判断点击位置)
			break;
		case WM_MOUSEMOVE:				// 鼠标移动
			break;
		case WM_RBUTTONUP:				// 鼠标右键释放
			break;
		}
	}
}

// 显示本关分数
void showScore()
{
	putimage(0, 0, &stu_project.imgScore);
	settextstyle(24, 0, "微软雅黑");
	settextcolor(YELLOW);
	setbkmode(TRANSPARENT);
	myDrawString(330, 58, to_string(stu_project.level + 1));
	settextcolor(WHITE);
	int score = 0;
	for (int i = 0; i < 4; i++)
	{
		score = score + stu_project.enemyArmorDeadNum[i] * 100 * (i + 1);
		myDrawString(176, 183 + i * 42 , to_string(stu_project.enemyArmorDeadNum[i]));
		myDrawString(220, 183 + i * 42, "×");
		myDrawString(260, 183 + i * 42, to_string(100 * (i + 1)));
		myDrawString(320, 183 + i * 42, "=");
		myDrawString(350, 183 + i * 42, to_string(stu_project.enemyArmorDeadNum[i] * 100 * (i + 1)));
		Sleep(500);
	}
	settextcolor(RED);
	myDrawString(350, 350, to_string(score));
	Sleep(500);
	system("pause");
}

// 处理游戏状态(下一关或失败)
void doGame()
{
	// 游戏结束
	if (stu_project.gameStatus == GAME_STATUS_OVER)
	{
		myPlayAudio("./resources/audio/over.mp3");
		myDrawImage((GAME_WIDTH - stu_project.imgFailure.getwidth()) / 2, (GAME_HEIGHT - stu_project.imgFailure.getheight()) / 2, &stu_project.imgFailure);
		Sleep(1000);
		showScore();
	}
	else if (stu_project.gameStatus == GAME_STATUS_WIN)
	{
		myDrawImage((GAME_WIDTH - stu_project.imgSuccess.getwidth()) / 2, (GAME_HEIGHT - stu_project.imgSuccess.getheight()) / 2, &stu_project.imgSuccess);
		Sleep(1000);
		showScore();
		stu_project.level++;
		if (stu_project.level < GameMap::getMaxLevel())
		{
			newGame();
		}
	}

}

// 开始游戏
void newGame()
{
	myPlayAudio("./resources/audio/begin.mp3");

	// 初始化游戏
	initGame();

	// 开始游戏
	while (stu_project.gameStatus == GAME_STATUS_RUN)
	{
		// 开始刷新
		if (myTimer(INTERVAL_REFRESH, TIMERID_REFRESH))
		{
			// 绘制窗口
			paint();

			// 游戏进程
			run();
		}

		// 键盘监控
		keyEvent();

		// 鼠标监控(必须随时监控,否则不湿滑)
		//mouseEvent();
	}

	// 处理游戏状态(下一关或失败)
	doGame();
}

下载:

链接:https://pan.baidu.com/s/1Mk-yTrfrXnb-FmYO82YA4A?pwd=g67n 
提取码:g67n

  • 6
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
游戏分里外两个部分组成,里部分(用户不可见) 通过里部分执行判断,地图数组更改,和各种值的改变。更改完里部分再根据相应变化更改表部分。(用户可视部分)表部分的打印通过gotoxy去到相应坐标再printf打印出字符,通过文本函数改变文字字体颜色与文字背景颜色与字符组合实现图形界面。 程序通过 计数器+循环判断 的思想,类似单核cpu的多线程实现(单线程在不同程序/函数间来回执行)省去了多线程。(具体过程在功能设计与描述有详细描述) 另AI实现与加强依赖于rand随机函数的运用,进一步强化AI,增加游戏乐趣 功能方面,游戏参考于80年代任天堂红白机(FC/FamilyComputer)上的游戏坦克大战(Battle City),包括地图,游戏模式等等(当时的游戏直接烧在电路板上)。所以游戏平衡方面已经有了很好的参考,无需再花大量时间测试平衡性。 但诸如地图中的树林元素,随机道具等没有实现。但较之原版,该游戏由C/C++编写PC运行,由字符界面实现游戏画面。原版一辆坦克的子弹未消失之前不能发射第二颗。导致子弹打击远处CD长,近处CD短。该游戏每个子弹都有相同CD,子弹未消失只要CD达到即可发射第二颗,第三颗…增加了真实性,相较于原版是个改进。且考虑到PC性能不一内置了游戏速度调整。玩家可根据PC性能调整至合适的速度。
坦克大战是一款经典的游戏,可以用C++和Windows.h库来实现。下面是一个简单的实现示例: ```cpp #include <iostream> #include <Windows.h> using namespace std; const int MAP_WIDTH = 20; const int MAP_HEIGHT = 20; const int TANK_SIZE = 3; const int BULLET_SIZE = 1; char g_map[MAP_HEIGHT][MAP_WIDTH]; class Tank { public: Tank(int x, int y, char direction) : m_x(x), m_y(y), m_direction(direction) { for (int i = 0; i < TANK_SIZE; i++) { g_map[y][x + i] = 'T'; } } void move(char direction) { switch (direction) { case 'w': if (m_y > 0 && g_map[m_y - 1][m_x] == ' ') { clear(); m_y--; draw(); } break; case 's': if (m_y < MAP_HEIGHT - 1 && g_map[m_y + TANK_SIZE][m_x] == ' ') { clear(); m_y++; draw(); } break; case 'a': if (m_x > 0 && g_map[m_y][m_x - 1] == ' ') { clear(); m_x--; draw(); } break; case 'd': if (m_x < MAP_WIDTH - TANK_SIZE && g_map[m_y][m_x + TANK_SIZE] == ' ') { clear(); m_x++; draw(); } break; default: break; } m_direction = direction; } void fire() { Bullet bullet(m_x + TANK_SIZE / 2, m_y + TANK_SIZE / 2, m_direction); } private: void draw() { for (int i = 0; i < TANK_SIZE; i++) { g_map[m_y][m_x + i] = 'T'; } } void clear() { for (int i = 0; i < TANK_SIZE; i++) { g_map[m_y][m_x + i] = ' '; } } int m_x; int m_y; char m_direction; }; class Bullet { public: Bullet(int x, int y, char direction) : m_x(x), m_y(y), m_direction(direction) { g_map[y][x] = 'B'; } void move() { switch (m_direction) { case 'w': if (m_y > 0 && g_map[m_y - 1][m_x] == ' ') { clear(); m_y--; draw(); } else { clear(); } break; case 's': if (m_y < MAP_HEIGHT - 1 && g_map[m_y + 1][m_x] == ' ') { clear(); m_y++; draw(); } else { clear(); } break; case 'a': if (m_x > 0 && g_map[m_y][m_x - 1] == ' ') { clear(); m_x--; draw(); } else { clear(); } break; case 'd': if (m_x < MAP_WIDTH - 1 && g_map[m_y][m_x + 1] == ' ') { clear(); m_x++; draw(); } else { clear(); } break; default: break; } } private: void draw() { g_map[m_y][m_x] = 'B'; } void clear() { g_map[m_y][m_x] = ' '; } int m_x; int m_y; char m_direction; }; void initMap() { for (int i = 0; i < MAP_HEIGHT; i++) { for (int j = 0; j < MAP_WIDTH; j++) { if (i == 0 || i == MAP_HEIGHT - 1 || j == 0 || j == MAP_WIDTH - 1) { g_map[i][j] = '#'; } else { g_map[i][j] = ' '; } } } } void printMap() { system("cls"); for (int i = 0; i < MAP_HEIGHT; i++) { for (int j = 0; j < MAP_WIDTH; j++) { cout << g_map[i][j]; } cout << endl; } } int main() { initMap(); Tank tank(1, 1, 'd'); while (true) { printMap(); char input = getchar(); if (input == ' ') { tank.fire(); } else { tank.move(input); } Sleep(100); } return 0; } ``` 这是一个简单的示例,你可以根据需要进行修改和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值