C++————坦克大战

C++所实现的一个坦克大战小游戏,代码略渣,可以供新手参考,实现了坦克的自动寻路,玩家的自定义地图等功能,读档和存档还可优化
链接: https://pan.baidu.com/s/15Wc7yEvdsZ9yN0zEiwjcdw 提取码: qu5c
C++————坦克大战_第1张图片
C++————坦克大战_第2张图片
CAstar.h

#pragma once
#include "CTankObject.h"

class CTankObject;
class CAStar
{
public:
	CAStar();
	~CAStar();
private:
	//带方向的坐标点;
	typedef struct _MY_COORD :public COORD
	{
		bool operator==(const COORD&cod)
		{
			return (X == cod.X) && (Y == cod.Y);
		}
		void operator=(const COORD& cod)
		{
			X = cod.X;
			Y = cod.Y;
		}
		int NewDir;				 //新方向;		
	}MY_COORD, *PMY_CORRD;

	//寻路点;
	typedef struct _NODE_INFO
	{
		int GPath;	//移动损耗;
		int HPath;	//距离终点最短距离;
		int FPath;	//G+H;

		void SetH_F(const COORD& cod1, const COORD& cod2)
		{
			HPath = abs(cod1.X - cod2.X) + abs(cod1.Y - cod2.Y);
			FPath = GPath + HPath;
		}

		MY_COORD codSelf;		 //自身坐标;
		MY_COORD codParent;		 //父坐标;			
	}NODE_INFO, *PNODE_INFO;


	//=====优化处理====
	typedef struct _VIR_INFO
	{
		char isOpen : 1; //表是否在Open表中
		char isClose : 1; //表示是否在CLose表中
		char rcieve : 6; //保留
	}VIR_INFO, *PVIR_INFO;

	static PVIR_INFO m_pVir; //指向虚拟地图的首地址

	//地图处理;
	int nArr[MAP_Y][MAP_X] = {};

	COORD m_Star;				//起点;
	COORD m_End;				//终点;

	vector m_Open;	//待检测点;
	vector m_Close;	//已检测点;

	bool m_bIsMapInit;			//判断地图初始化完成;
	bool m_bIsCoordInit;		//判断坐标初始化完成;	

	bool InitCoord(const CTankObject& TankObj, const vector& vecTank);	//初始化坐标;
	void InitMapInfo(const CTankObject& TankObj, CMapObject * pMap);					//初始化地图;

	bool FindPath();			//包含最短路径的点;
	void GetPath();				//得到最短路径;
	CMapObject* m_pMapObject;	//地图;

public:
	bool Astar(CMapObject* pMap, const CTankObject& TankObj, const vector& vecTank);//主程序;
	vector  m_Path;	//最短路径坐标;
};

CBulletObject.h

#pragma once

#include "CDrawObject.h"
#include "CTankObject.h"
#include "CGameObject.h"

#include 
using std::vector;

//声明坦克;
class CTankObject;

class CBulletObject 
{
public:
	CBulletObject() = default;							//默认构造函数;
	CBulletObject(const CTankObject &TankObject);		//创建子弹;
	~CBulletObject();

	bool DrawObject();									//绘制子弹;
	bool ClsObject();									//擦除子弹;


	bool BulletMove(vector& vecTank, vector& vecBullet);			//子弹移动;
	bool BulletCollisio(vector& vecTank, vector& vecBullet);		//子弹碰撞检测;
	void BulletCrit();																			//子弹一次打一排三个;

	bool operator=(const CTankObject& TankObject);					//等号重载;将坦克信息赋值给子弹;
	bool operator==(CTankObject & TankObject);						//重载==;对比坦克信息;
	bool operator==(CBulletObject & BulletObject);					//重载==;对比子弹信息;

	void SetMapObject(CMapObject* val) { m_pMapObject = val; }		//设置地图值;用于读档;

public:
	bool GetIsDie() const { return m_bIsDie; }						//获取生存信息;
	bool GetCamp() const { return m_bCamp; }						//获取阵营;
	int GetPosX() const { return m_nPosX; }							//获取X坐标;
	int GetPosY() const { return m_nPosY; }							//获取Y坐标;
	int GetDir() const { return m_nDir; }							//获取方向;
	int GetID() const { return m_nID; }								//获取ID;
	int GetLevel() const { return m_nLevel; }						//获取等级;
	int GetSpeed() const { return m_nSpeed; }						//获取速度;

private:
	bool m_bIsDie;	//生存信息;
	bool m_bCamp;	//阵营;
	int m_nPosX;	//坐标X;
	int m_nPosY;	//坐标Y
	int m_nDir;		//方向;
	int m_nID;		//ID;
	int m_nLevel;	//等级;
	int m_nSpeed;	//速度;
	CMapObject* m_pMapObject;//地图;
};


CDrawObject.h

#pragma once
#include 
#include 
class CDrawObject
{
public:
	//绘制字符;
	static void WriteChar(int x, int y,const char* info, int color = 0);
	//绘制数字;
	static void WriteInt(int x, int y, int info, int color = 0);		
	
};

CGameObject.h

#pragma once
#include "CMapObject.h"
#include "CDrawObject.h"
#include "CTankObject.h"
#include "CBulletObject.h" 

#include 
using std::vector;
//播放音乐;
#pragma comment(lib, "Winmm.lib")  

//声明坦克;子弹;
class CBulletObject;
class CTankObject;

class CGameObject
{
public:
	CGameObject();
	~CGameObject();

	void Welcome();				//选项菜单


	bool StartGame();			//游戏开始	
	void Show();				//游戏开始界面
	void Victory();				//胜利;
	void GameOver();			//失败;
	void ClearData();			//清空数据

	void SaveData();			//存档
	void ReadData();			//读档	
	void ReadGameMenu();		//读取自定义游戏

	void FirstPlayer();			//玩家1操作
	void SecondPlayer();		//玩家2操作

	void MoveNPC();				//NPC动作;
	void BulletAction();		//子弹动作;

	bool IniTank();				//初始化坦克;
	void SetWindowsInfo();		//设置控制台信息
	void DrawEnemy(int nRound, int nEnemy);				//绘制关卡;敌人数量
private:
	int PlayerACount;						//玩家1计数器;控制发射子弹速度
	int PlayerBCount;						//玩家2计数器;控制发射子弹速度

	bool m_rSavaMap;						//读取自定义地图标志
	bool m_bData;							//读档标志
	bool m_bDouble;							//双人模式
	int m_nRound;							//关卡
	int m_nEnemy;							//敌人数量

	CMapObject m_nMapObject;				//地图

	int m_nTank;							//坦克数量;存档读档使用
	vector m_vecTankObject;	//坦克数组
	int m_nBullet;							//子弹数量;存档读档使用
	vector m_vecBulletObject;//子弹数组
	char Maparr[100][30];					//地图名数组
};

CMapObject.h

#pragma once
#include 
#include 
using std::vector;


			
//方向;
enum DIR
{
	UP = 0,
	DOWN = 1,
	LEFT = 2,
	RIGHT = 3,
};

//地图数组中保存的值;
enum M_VALUE
{

	空地 = 0,		//空;
	边界 = 1,		//边界;
	钢墙 = 2,		//钢墙;
	土墙 = 3,		//土墙;
	丛林 = 4,		//丛林;
	河 = 5,			//河水;
	基地 = 6,		//基地;
	子弹 = 7,		//子弹;

	GAMEPLAYER_1 = 10,	//玩家A
	GAMEPLAYER_2 = 11,	//玩家B

	NPCTANK2 = 12,	//NPC
	NPCTANK3 = 13,
	NPCTANK4 = 14,
	NPCTANK5 = 15,
	NPCTANK6 = 16,
	NPCTANK7 = 17,
	NPCTANK8 = 18,
	NPCTANK9 = 19
};

//地图宽高;
#define MAP_X 75
#define MAP_Y 50



static int NumberMap = 0;			//记录地图数量
extern int m_nStage;			//编辑地图的关卡;

//声明坦克;
class CTankObject;

class CMapObject
{
public:
	CMapObject();
	~CMapObject();

	bool SetMapValue(int nPosX, int nPosY, int Value);	//设置地图值
	int  GetMapValue(int nPosX, int nPosY);				//获取地图值
	bool DrawMap();										//绘制地图
	void ReadMap(int m_nRound);							//根据关卡值读取相应地图
	void ReadSaveMap();									//读取自定义地图
	bool DIYEditMap();									//DIY地图主程序
	void DrawGanmeInfo();								//绘制游戏信息
	void DrawScore(vector& vecTank);		//绘制分数
	

	
	
	int** GetPMap() const { return (int **)m_nMap; };		//二维数组转一维;A星寻路中用;

private:

	bool IniMap();										//初始化地图
	void DIYMapInfo();									//DIY地图信息
	void OutPutPos(int nPosX, int nPoxY);				//DIY地图输出坐标
	bool MouseEventProc(MOUSE_EVENT_RECORD StcMouse);	//鼠标事件
	bool MouseMove(MOUSE_EVENT_RECORD &StcMouse);		//鼠标拖动
	bool MouseClick(MOUSE_EVENT_RECORD &StcMouse);		//鼠标点击
	bool KeyEventProc(KEY_EVENT_RECORD &StcKeyEvent);	//键盘事件
	void SaveMap();				                        //保存地图
private:
	int m_nMapVlue;						//编辑地图时写入地图值;
	int m_nMap[MAP_Y][MAP_X] = {};	//地图;
};

CTankObject.h

#pragma once
#include "CMapObject.h"
#include "CGameObject.h"
#include 
using std::vector;

class CBulletObject;

class CTankObject 
{
public:
	CTankObject() = default;															//默认构造函数;
	CTankObject(int PosX, int PosY, int Dir, bool Group, int ID, CMapObject* Object);		//初始化坦克;
	~CTankObject();
	bool DrawObject();																	//绘制坦克;
	bool ClsObject();																	//擦除坦克;
	bool MoveTank(int nDir);															//坦克移动;
	bool MoveNpc(const vector& vecTank, vector& vecBullet);	//NPC移动;
	bool Search();							

	bool TankCollision();											//坦克碰撞;
	void SetLevel(int val) { m_nLevel = val; }						//设置坦克等级;
	void SetScores(int val) { m_nScores = val; }					//增加分数;
	void SetMapObject(CMapObject* val) { m_pMapObject = val; }		//设置地图;读档用;		
	CMapObject* GetMapObject() const { return m_pMapObject; }		//获取地图;赋值给子弹;

public:
	void SetIsDie(bool val) { m_bIsDie = val; }			//设置生存信息;
	bool GetIsDie() const { return m_bIsDie; }			//获取生存信息;
	bool GetGroup() const { return m_bGroup; }			//阵营;
	int GetPosX() const { return m_nPosX; }				//X坐标;
	int GetPosY() const { return m_nPosY; }				//Y坐标;
	int GetDir() const { return m_nDir; }				//方向;
	int GetLevel() const { return m_nLevel; }			//等级;
	int GetSpeed() const { return m_nSpeed; }			//速度;
	int GetScores() const { return m_nScores; }			//分数;
	int GetID() const { return m_nID; }					//ID;

private:
	bool m_bIsDie;		//生存;
	bool m_bGroup;		//阵营;
	int m_nPosX;		//X坐标;
	int m_nPosY;		//Y坐标;
	int m_nDir;			//方向;
	int m_nID;			//ID;
	int m_nLevel;		//等级;
	int m_nSpeed;		//速度;		
	int m_nScores;		//分数;

	
	int NPCCount;							//NPC计数器;控制NPC发射子弹速度;
	CMapObject* m_pMapObject;				//地图;
	static const int m_TankShape[4][3][3];	//坦克图形;
	static const int m_ColorNPC[3];			//NPC颜色;
	static const int m_TankSpeed[3];		//速度控制;等级作为下标;
};

CAstar.cpp

#include "CAStar.h"

CAStar::PVIR_INFO CAStar::m_pVir;

CAStar::CAStar() {}

CAStar::~CAStar() {}

//A星寻路
bool CAStar::Astar(CMapObject* pMap, const CTankObject& TankObj, const vector& vecTank) {
	//初始化坐标;
	if (!InitCoord(TankObj, vecTank)) {
		return false;
	}


	//更新地图;
	InitMapInfo(TankObj, pMap);


	//寻路;
	if (FindPath())
	{
		//获取路径;
		GetPath();
		return true;
	}
	else
		return false;

}

//初始化坐标
bool CAStar::InitCoord(const CTankObject& TankObj, const vector& vecTank)
{
	m_Star.X = TankObj.GetPosX();
	m_Star.Y = TankObj.GetPosY();


	m_End.X = vecTank[0].GetPosX();
	m_End.Y = vecTank[0].GetPosY();

	//已在同一条线使用十字寻路;
	if (m_Star.X == m_End.X || m_Star.X == m_End.X + 1 || m_Star.X == m_End.X - 1
		|| m_Star.Y == m_End.Y || m_Star.Y == m_End.Y + 1 || m_Star.X == m_End.Y - 1)
	{
		return false;
	}

	m_bIsCoordInit = true;
	return true;

}


//初始化寻路地图
void CAStar::InitMapInfo(const CTankObject& TankObj, CMapObject* pMap)
{
	//处理地图;
	m_pMapObject = pMap;
	memcpy_s(nArr, sizeof(int) * 75 * 50, m_pMapObject->GetPMap(), sizeof(int) * 75 * 50);

	for (int i = 1; i < MAP_Y - 1; i++)
	{
		for (int j = 1; j < MAP_X - 1; j++)
		{

			if (nArr[i][j] != 空地 || nArr[i][j] != TankObj.GetID())
			{
				nArr[i][j] = 1;
			}
			else
			{
				nArr[i][j] = 0;
			}
		}
	}

	m_bIsMapInit = true;
}


//搜索路径
bool CAStar::FindPath()
{

	//判断初始化;
	if (!m_bIsMapInit || !m_bIsCoordInit)
	{
		return false;
	}

	//清空表;
	m_Open.clear();
	m_Close.clear();

	if (m_pVir) {
		ZeroMemory(m_pVir, MAP_Y*MAP_X);
	}
	//起点加入Open表;
	NODE_INFO nodeStart;
	nodeStart.codSelf = m_Star;
	nodeStart.codSelf.NewDir = 1;
	nodeStart.GPath = 0;
	nodeStart.SetH_F(m_Star, m_End);

	m_Open.push_back(nodeStart);

	//循环寻路;
	while (true)
	{
		//Open表为空;未找到路径;
		if (m_Open.empty())
		{
			return false;
		}

		//从Open表中找到F值最小的点扩散;
		int nIndex = 0;
		for (unsigned int i = 1; i < m_Open.size(); i++)
		{
			if (m_Open[nIndex].FPath > m_Open[i].FPath)
			{
				nIndex = i;
			}
		}

		//扩散四个点;
		NODE_INFO nodeNew[4];
		//上;
		nodeNew[0].codSelf.X = m_Open[nIndex].codSelf.X;
		nodeNew[0].codSelf.Y = m_Open[nIndex].codSelf.Y - 1;
		//下;
		nodeNew[1].codSelf.X = m_Open[nIndex].codSelf.X;
		nodeNew[1].codSelf.Y = m_Open[nIndex].codSelf.Y + 1;
		//左;
		nodeNew[2].codSelf.X = m_Open[nIndex].codSelf.X - 1;
		nodeNew[2].codSelf.Y = m_Open[nIndex].codSelf.Y;
		//右;
		nodeNew[3].codSelf.X = m_Open[nIndex].codSelf.X + 1;
		nodeNew[3].codSelf.Y = m_Open[nIndex].codSelf.Y;

		//赋值方向;G;H;F;
		//将当前节点作为扩散的节点(上下左右)的父节点
		for (int j = 0; j < 4; j++)
		{
			nodeNew[j].codParent = m_Open[nIndex].codSelf;
			nodeNew[j].codSelf.NewDir = j;
			nodeNew[j].GPath = m_Open[nIndex].GPath + 1;

			nodeNew[j].SetH_F(nodeNew[j].codSelf, m_End);
		}

		if (m_pVir) {
			//=============
			//m_pVir中标志当前节点放在close表中还是open表中
			int x1 = m_Open[nIndex].codSelf.X;
			int y1 = m_Open[nIndex].codSelf.Y;
			m_pVir[y1 * MAP_X + x1].isClose = true;
			m_pVir[y1 * MAP_X + x1].isOpen = false;
			//=============
		}

		//添加基点到Close表;并从Open表中删除;
		m_Close.push_back(m_Open[nIndex]);
		m_Open.erase(m_Open.begin() + nIndex);

		//循环判断四个点是否合格;
		for (int i = 0; i < 4; i++)
		{
			int x = nodeNew[i].codSelf.X;
			int y = nodeNew[i].codSelf.Y;

			//判断是否是终点;是就直接返回;说明已到达;
			//坦克体积较大;判断以坦克中心四周的四个点;
			bool flag1 = nodeNew[i].codSelf.X == m_End.X && nodeNew[i].codSelf.Y == m_End.Y - 2;	//上;
			bool flag2 = nodeNew[i].codSelf.X == m_End.X && nodeNew[i].codSelf.Y == m_End.Y + 2;	//下;
			bool flag3 = nodeNew[i].codSelf.Y == m_End.Y && nodeNew[i].codSelf.X == m_End.X - 2;	//左;
			bool flag4 = nodeNew[i].codSelf.Y == m_End.Y && nodeNew[i].codSelf.X == m_End.X + 2;	//右;

			if (flag1 || flag2 || flag3 || flag4)
			{
				m_Close.push_back(nodeNew[i]);
				return true;
			}

			//判断是否越界;越界就跳过
			if (x < 1 || x >= MAP_X - 2 ||
				y < 1 || y >= MAP_Y - 2)
			{
				continue;
			}


			//判断当前中心点的上下左右是否是障碍物,是障碍物就跳过
			if (nArr[(y - 1)][x] != 空地 || nArr[(y + 1)][x] != 空地 ||
				nArr[y][(x - 1)] != 空地 || nArr[y][(x + 1)] != 空地) {
				continue;
			}
			//判断是否在Open表或Close表中,不在就跳过
			if (m_pVir[y * MAP_X + x].isClose || m_pVir[y * MAP_X + x].isOpen) {
				continue;
			}

			//优化

			//将合格点存入Open表;
			m_Open.push_back(nodeNew[i]);

			if (m_pVir) {
				//============
				//在m_pVir表中标志该点在open表中
				m_pVir[y * MAP_X + x].isOpen = true;
				//============
			}
		}

	}
}


//回溯查找路径
void CAStar::GetPath()
{
	//清空;
	m_Path.clear();

	int nIndex = m_Close.size() - 1;

	//循环回溯;类似;
	while (true)
	{
		for (unsigned int i = 0; i < m_Close.size(); i++)
		{
			if (m_Close[nIndex].codSelf == m_Star)
			{
				return;
			}
			if (m_Close[nIndex].codParent == m_Close[i].codSelf)
			{
				m_Path.push_back(m_Close[nIndex].codParent);
				nIndex = i;
				break;
			}
		}
	}


	return;
}

CBulletObject.cpp

#include "CBulletObject.h"


//初始化子弹
CBulletObject::CBulletObject(const CTankObject& TankObject)
{
	*this = TankObject;
	switch (m_nDir)
	{
	case UP:		m_nPosY -= 2;		break;
	case DOWN:		m_nPosY += 2;		break;
	case LEFT:		m_nPosX -= 2;		break;
	case RIGHT:		m_nPosX += 2;		break;
	}
	//初始化子弹在边界无效;
	if (m_pMapObject->GetMapValue(m_nPosX, GetPosY()) == 1)
	{
		m_bIsDie = false;
	}
	//子弹等级低于2初始化在钢墙无效;
	else if (m_pMapObject->GetMapValue(m_nPosX, GetPosY()) == 2 && m_nLevel < 2)
	{
		m_bIsDie = false;
	}

	return;
}


CBulletObject::~CBulletObject() {}

//绘制子弹
bool CBulletObject::DrawObject()
{
	if (m_bCamp)
	{
		CDrawObject::WriteChar(m_nPosX, m_nPosY, "●", 4);
	}
	else
	{
		CDrawObject::WriteChar(m_nPosX, m_nPosY, "●", 2);
	}

	//跳过河流和丛林;
	if (m_pMapObject->GetMapValue(m_nPosX, m_nPosY) != 河 &&
		m_pMapObject->GetMapValue(m_nPosX, m_nPosY) != 丛林)
	{
		m_pMapObject->SetMapValue(m_nPosX, m_nPosY, 子弹);
	}
	return true;
}

//清除子弹
bool CBulletObject::ClsObject()
{
	CDrawObject::WriteChar(m_nPosX, m_nPosY, "  ");
	//跳过河流和草;
	if (m_pMapObject->GetMapValue(m_nPosX, m_nPosY) != 河 &&
		m_pMapObject->GetMapValue(m_nPosX, m_nPosY) != 丛林)
	{
		m_pMapObject->SetMapValue(m_nPosX, m_nPosY, 空地);
	}
	return true;
}

//子弹移动
bool CBulletObject::BulletMove(vector& vecTank, vector& vecBullet)
{
	CBulletObject BulletTemp = *this;
	switch (m_nDir)
	{
	case	UP:		BulletTemp.m_nPosY--;		break;
	case	DOWN:		BulletTemp.m_nPosY++;		break;
	case	LEFT:		BulletTemp.m_nPosX--;		break;
	case	RIGHT:		BulletTemp.m_nPosX++;		break;
	}

	//碰撞检测;
	if (BulletTemp.BulletCollisio(vecTank, vecBullet))
	{
		this->ClsObject();
		//重画河流;
		if (m_pMapObject->GetMapValue(m_nPosX, m_nPosY) == 河)
		{
			CDrawObject::WriteChar(m_nPosX, m_nPosY, "~", 9);
			m_pMapObject->SetMapValue(m_nPosX, m_nPosY, 河);
		}

		//重画草;
		if (m_pMapObject->GetMapValue(m_nPosX, m_nPosY) == 丛林)
		{
			CDrawObject::WriteChar(m_nPosX, m_nPosY, "※", 2);
			m_pMapObject->SetMapValue(m_nPosX, m_nPosY, 丛林);
		}
		*this = BulletTemp;
		this->DrawObject();
	}
	else
	{
		//碰撞检测失败标记子弹失效;
		this->ClsObject();
		this->m_bIsDie = false;
	}


	return true;
}


//子弹碰撞
bool CBulletObject::BulletCollisio(vector& vecTank, vector& vecBullet)
{
	//临时TankID;
	int nID = -1;

	switch (m_pMapObject->GetMapValue(m_nPosX, m_nPosY))
	{
	case 空地:
		return true;
		break;
	case 边界:
		return false;
		break;
	case 钢墙:
		if (this->m_nLevel < 2)
		{
			return false;
			break;
		}
		CDrawObject::WriteChar(this->m_nPosX, this->m_nPosY, "  ");
		m_pMapObject->SetMapValue(this->m_nPosX, this->m_nPosY, 空地);
		BulletCrit();
		return false;
		break;
	case 土墙:
		CDrawObject::WriteChar(this->m_nPosX, this->m_nPosY, "  ");
		m_pMapObject->SetMapValue(this->m_nPosX, this->m_nPosY, 空地);
		BulletCrit();
		return false;
		break;
	case 丛林:
	case 河:
		return true;
		break;
	case 基地:
		vecTank[0].SetIsDie(false);
		vecTank[1].SetIsDie(false);
		break;
		//子弹检测;
	case 子弹:
		//获取另一个子弹;
		for (auto& i : vecBullet)
		{
			//坐标相等且同阵营忽略;
			if (*this == i &&
				this->GetCamp() == i.GetCamp())
			{
				break;
			}
			//坐标相等阵营相反都失效;
			else if (*this == i &&
				this->GetCamp() != i.GetCamp())
			{
				i.m_bIsDie = false;
				i.ClsObject();
				this->m_bIsDie = false;
				return false;
				break;
			}
		}
		break;
	case  GAMEPLAYER_1:
	case  GAMEPLAYER_2:

		//打中玩家;		
		for (unsigned int i = 0; i < 2; i++)						//击中两次则死亡
		{
			if (*this == vecTank[i])
			{
				if (this->GetCamp() == vecTank[i].GetGroup())
				{
					return false;
					break;
				}
				else
				{
					nID = i;
				}
			}
		}

		//高级的降级;
		if (vecTank[nID].GetLevel() > 0)
		{
			int nLevel = vecTank[nID].GetLevel();
			nLevel -= 1;
			vecTank[nID].SetLevel(nLevel);
			return false;
			break;
		}
		else
		{
			vecTank[nID].ClsObject();
			vecTank[nID].SetIsDie(true);					//改为false就是击中两次死亡,true为无敌模式

		}

		return false;
		break;
	case  NPCTANK2:
	case  NPCTANK3:
	case  NPCTANK4:
	case  NPCTANK5:
	case  NPCTANK6:
	case  NPCTANK7:
	case  NPCTANK8:
	case  NPCTANK9:
		//打中敌军;		
		for (unsigned int i = 2; i < (vecTank.size()); i++)
		{
			if (*this == vecTank[i])
			{
				if (this->GetCamp() == vecTank[i].GetGroup())
				{
					return false;
					break;
				}
				else
				{
					nID = i;
				}
			}
		}

		//高级的降级;
		if (vecTank[nID].GetLevel() > 0)
		{
			int nLevel = vecTank[nID].GetLevel();
			nLevel -= 1;
			vecTank[nID].SetLevel(nLevel);

			//加分;
			int nScore = vecTank[this->m_nID % 10].GetScores();
			nScore += 100;
			vecTank[this->m_nID % 10].SetScores(nScore);

			//刷新分数;
			m_pMapObject->DrawScore(vecTank);

			return false;
			break;
		}

		else
		{
			//低级死亡
			vecTank[nID].ClsObject();
			vecTank[nID].SetIsDie(false);

			//加分;
			int nScore = vecTank[this->m_nID % 10].GetScores();
			nScore += 200;
			vecTank[this->m_nID % 10].SetScores(nScore);

			//刷新分数;
			m_pMapObject->DrawScore(vecTank);

			return false;
			break;
		}
	default:
		break;
	}
	return true;
}


//一发子弹打三个
void CBulletObject::BulletCrit()
{
	if ((this->m_nPosX > 1 || this->m_nPosX < 57) &&
		(this->m_nDir == UP || this->m_nDir == DOWN)
		&& this->m_nLevel > 0)
	{
		CDrawObject::WriteChar(this->m_nPosX + 1, this->m_nPosY, "  ");
		m_pMapObject->SetMapValue(this->m_nPosX + 1, this->m_nPosY, 空地);
		CDrawObject::WriteChar(this->m_nPosX - 1, this->m_nPosY, "  ");
		m_pMapObject->SetMapValue(this->m_nPosX - 1, this->m_nPosY, 空地);
		return;
	}
	else if ((this->m_nPosY > 1 || this->m_nPosY < 47) &&
		(this->m_nDir == LEFT || this->m_nDir == RIGHT)
		&& this->m_nLevel > 0)
	{
		CDrawObject::WriteChar(this->m_nPosX, this->m_nPosY + 1, "  ");
		m_pMapObject->SetMapValue(this->m_nPosX, this->m_nPosY + 1, 空地);
		CDrawObject::WriteChar(this->m_nPosX, this->m_nPosY - 1, "  ");
		m_pMapObject->SetMapValue(this->m_nPosX, this->m_nPosY - 1, 空地);
		return;
	}
}

//子弹与子弹对比
bool CBulletObject::operator==(CBulletObject & BulletObject)
{
	if (this->m_nPosX == BulletObject.GetPosX() &&
		this->m_nPosY == BulletObject.GetPosY())
	{
		return true;
	}
	else
	{
		return false;
	}
}


//子弹与坦克对比
bool CBulletObject::operator==(CTankObject & TankObject)
{

	//遍历坦克形状;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			//循环检测9个点;
			int nTempX = TankObject.GetPosX() + i - 1;
			int nTempY = TankObject.GetPosY() + j - 1;

			//存在相等即打中;
			if (nTempX == m_nPosX &&
				nTempY == nTempY)
			{
				return true;
			}

		}
	}
	//未检测到没打中;
	return false;
}


//坦克信息赋值给子弹  重载=
bool CBulletObject::operator=(const CTankObject& TankObject)
{
	m_bIsDie = TankObject.GetIsDie();
	m_bCamp = TankObject.GetGroup();

	m_nPosX = TankObject.GetPosX();
	m_nPosY = TankObject.GetPosY();
	m_nDir = TankObject.GetDir();

	m_nID = TankObject.GetID();
	m_nLevel = TankObject.GetLevel();
	m_nSpeed = TankObject.GetSpeed() * 2;
	m_pMapObject = TankObject.GetMapObject();

	return true;
}

CDrawObject.cpp

#include 
#include "CDrawObject.h"
#include "CMapObject.h"



//绘制字符
void CDrawObject::WriteChar(int x, int y,const char* info, int color)
{
	CONSOLE_CURSOR_INFO cci;
	cci.dwSize = 1;
	cci.bVisible = false;//不显示光标
	HANDLE hOutStd = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorInfo(hOutStd, &cci);
	COORD temp = { x*2, y };
	SetConsoleCursorPosition(hOutStd, temp);
	SetConsoleTextAttribute(hOutStd, color);
	printf("%s", info);
}
//绘制数字;
void CDrawObject::WriteInt(int x, int y, int info, int color)
{
	CONSOLE_CURSOR_INFO cci;
	cci.dwSize = 1;
	cci.bVisible = false;//不显示光标
	HANDLE hOutStd = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorInfo(hOutStd, &cci);
	COORD temp = { x*2,y };
	SetConsoleCursorPosition(hOutStd, temp);
	SetConsoleTextAttribute(hOutStd, color);
	printf("%d", info);
}

CGameObject.cpp

#include "CGameObject.h"
#include "CTankObject.h"
#include "CMapObject.h"
#include "CBulletObject.h"

#include 
#include 
#include 
#include 

#pragma comment(lib,"winmm.lib")
using std::cout;

int m_Enemy;
//声明子弹;
class CBulletObject;

//获取按键;
#define KEY_DOWN(key) (GetAsyncKeyState(key) & 0x8000) ? 1 : 0		//判断按键是否按下


CGameObject::CGameObject() {
	m_nRound = 1;
}

CGameObject::~CGameObject() {}

//游戏欢迎界面
void CGameObject::Welcome()
{
	SetWindowsInfo();								//设置窗口标题和大小
	system("color 0A");								
	system("cls");									
	Show();											//欢迎界面
	

	while (true)
	{
		if (KEY_DOWN(0x31))					//判断用户是否按键
		{
			m_bDouble = false;				//单人模式
			m_bData = false;
			m_rSavaMap = false;
			m_nEnemy = 10;					//设定敌人数量10
			if (m_nRound)					//如果不是初始关卡就恢复为初始关卡
			{
				m_nRound = 1;				
			}
			if (m_nStage != 0)				//如果关卡标记不为零,就赋值,从当前标记开始
			{
				m_nRound = m_nStage;
			}			
			StartGame();						//游戏开始	
		}
		if (KEY_DOWN(0x32))
		{
			m_bDouble = true;				//双人模式
			m_bData = false;
			m_rSavaMap = false;
			m_nEnemy = 20;					//设定敌人数量20
			if (m_nRound)
			{
				m_nRound = 1;				
			}
			if (m_nStage != 0)
			{
				m_nRound = m_nStage;
			}
			StartGame();					//游戏开始	
		}
		if (KEY_DOWN(0x33))
		{
			system("cls");
			while (true)
			{				
				CDrawObject::WriteChar(34, 20, " 1  读取游戏 ", 7);
				CDrawObject::WriteChar(34, 23, " 2  读取地图 ", 7);
				if (KEY_DOWN(0x31))
				{
					ReadData();
				}
				if (KEY_DOWN(0x32))
				{
					m_bDouble = false;				//单人模式
					m_bData = true;
					m_rSavaMap = true;
					m_nEnemy = 10;					//设定敌人数量10	
					StartGame();
				}
				if (KEY_DOWN(VK_ESCAPE))
				{
					Welcome();
				}
			}
		}
		if (KEY_DOWN(0x34))
		{
			m_nMapObject.DIYEditMap();						//自定义地图
			Welcome();										//重新进入
		}
		if (KEY_DOWN(0x35))
		{
			exit(0);										//无条件退出
		}
	}
	
}


//开始游戏
bool CGameObject::StartGame()
{	

	if (!m_bData)								//判断是否开始新游戏存档
	{
		m_nMapObject.ReadMap(m_nRound);
		IniTank();
	}
	if (m_rSavaMap)								//判断是否使用自定义地图
	{
		m_nMapObject.ReadSaveMap();
		IniTank();
	}

	m_nMapObject.DrawMap();					//画地图
	m_nMapObject.DrawGanmeInfo();			//显示侧边信息
	m_vecTankObject[0].DrawObject();		//画坦克

	if (m_bDouble)							//判断是否双人
	{
		m_vecTankObject[1].SetIsDie(true);	//添加坦克信息
		m_vecTankObject[1].SetLevel(1);
		m_vecTankObject[1].DrawObject();
	}

	//恢复读档
	if (m_bData)						
	{
		m_bData = false;
	}

	clock_t tPlayerA = clock(),				//记录时间
			tPlayerB = clock(),
			tTankNPC = clock(),
			tBullet = clock();

	PlaySoundA("Tankshow.wav", NULL, SND_ASYNC | SND_NODEFAULT);		//播放开始音效
	
	
	

	while (true)
	{
		DrawEnemy(m_nRound, m_nEnemy);					//输出关卡信息
		m_nMapObject.DrawScore(m_vecTankObject);		//显示玩家坦克当前得分和等级

		//玩家1移动;
		if (clock() - tPlayerA > m_vecTankObject[0].GetSpeed()
			&& m_vecTankObject[0].GetIsDie())
		{
			FirstPlayer();								//玩家一操作
			tPlayerA = clock();
		}

		//玩家2移动;
		if (clock() - tPlayerB > m_vecTankObject[1].GetSpeed()
			&& m_vecTankObject[1].GetIsDie())
		{
			SecondPlayer();								//玩家二操作
			tPlayerB = clock();
		}

		//移动TankNPC;
		if (clock() - tTankNPC > 100)
		{
			MoveNPC();
			tTankNPC = clock();

		}

		//子弹移动;
		if (clock() - tBullet > 50)
		{
			BulletAction();
			tBullet = clock();
		}


		//玩家死亡
		if (!m_vecTankObject[0].GetIsDie() &&
			!m_vecTankObject[1].GetIsDie())
		{
			GameOver();
		}

		//玩家胜利;
		if (m_nEnemy == 0)
		{
			Victory();
		}
	}

	return true;
}


//第一个玩家
void CGameObject::FirstPlayer()
{
	if (KEY_DOWN('W'))
		m_vecTankObject[0].MoveTank(UP);
	if (KEY_DOWN('S'))
		m_vecTankObject[0].MoveTank(DOWN);
	if (KEY_DOWN('A'))
		m_vecTankObject[0].MoveTank(LEFT);
	if (KEY_DOWN('D'))
		m_vecTankObject[0].MoveTank(RIGHT);
	//B键存档;
	if (KEY_DOWN('B'))
	{
		SaveData();
		CDrawObject::WriteChar(62, 31, "游戏存档已保存", 7);
		Sleep(2000);
		CDrawObject::WriteChar(62, 31, "              ");
	}
	
	//暂停游戏
	if (KEY_DOWN('P'))
	{
		while (true)				//进入另一个循环,按键按下跳出
		{
			CDrawObject::WriteChar(62, 34, "游戏已暂停", 4);
			CDrawObject::WriteChar(62, 36, "O键 游戏继续", 2);
			if (KEY_DOWN('O'))
			{
				break;
			}
		}
	}
	
	//ESC返回主菜单;
	else if (KEY_DOWN(VK_ESCAPE))
	{
		ClearData();
		Welcome();
	}

	//通过计数器限制发射速度;
	this->PlayerACount++;

	if ((KEY_DOWN('J')) && this->PlayerACount >
		(6 - m_vecTankObject[0].GetLevel() * 2))
	{
		PlaySoundA("fire.wav", NULL, SND_ASYNC | SND_NODEFAULT);		//播放击杀音效
		CBulletObject BulletObject(m_vecTankObject[0]);
		m_vecBulletObject.push_back(BulletObject);
		this->PlayerACount = 0;
	}
}


//第二个玩家
void CGameObject::SecondPlayer()
{
	if (KEY_DOWN(VK_UP))
		m_vecTankObject[1].MoveTank(UP);
	else if (KEY_DOWN(VK_DOWN))
		m_vecTankObject[1].MoveTank(DOWN);
	else if (KEY_DOWN(VK_LEFT))
		m_vecTankObject[1].MoveTank(LEFT);
	else if (KEY_DOWN(VK_RIGHT))
		m_vecTankObject[1].MoveTank(RIGHT);
	//发射;
	this->PlayerBCount++;
	if ((KEY_DOWN(VK_NUMPAD0)) && this->PlayerBCount >
		(6 - m_vecTankObject[0].GetLevel() * 2))
	{
		CBulletObject BulletObject(m_vecTankObject[1]);
		m_vecBulletObject.push_back(BulletObject);
		PlayerBCount = 0;
	}
}


//移动npc
void CGameObject::MoveNPC()
{
	for (unsigned int i = 2; i < m_vecTankObject.size();)
	{
		if (m_vecTankObject[i].GetIsDie())			//如果坦克存活,移动坦克
		{
			m_vecTankObject[i].MoveNpc(m_vecTankObject, m_vecBulletObject);
			i++;
		}
		else
		{
			//删除NPC;
			m_vecTankObject.erase(m_vecTankObject.begin() + i);
			m_nEnemy -= 1;
			PlaySoundA("bang.wav", NULL, SND_ASYNC | SND_NODEFAULT);		//播放击杀音效

			//更新关卡信息
			DrawEnemy(m_nRound, m_nEnemy);
			CDrawObject::WriteChar(68, 5, "  " , 6);
	
			if (m_nEnemy > 2)
			{
				//NPC重生;
				int nTemp = rand() % 3;
				switch (nTemp)											//根据随机数选择重生点
				{
				case 0:
				{
					CTankObject NPC(2, 2, DOWN, false, 12, &m_nMapObject);		//根据传入信息初始化坦克
					NPC.SetLevel(rand() % 3);									//坦克等级随机
					m_vecTankObject.push_back(NPC);
				}
				break;
				case 1:
				{
					CTankObject NPC(30, 2, DOWN, false, 13, &m_nMapObject);
					NPC.SetLevel(rand() % 3);
					m_vecTankObject.push_back(NPC);
				}
				break;
				case 2:
				{
					CTankObject NPC(57, 2, DOWN, false, 14, &m_nMapObject);
					NPC.SetLevel(rand() % 3);
					m_vecTankObject.push_back(NPC);
				}
				break;
				}
			}
		}
	}
	return;
}

//子弹移动
void CGameObject::BulletAction()
{
	for (unsigned int i = 0; i < m_vecBulletObject.size(); )
	{
		if (m_vecBulletObject[i].GetIsDie())				//如果子弹存在,移动子弹
		{
			//移动有效子弹;
			m_vecBulletObject[i].BulletMove(m_vecTankObject, m_vecBulletObject);
			i++;
		}
		else
		{
			//删除无效子弹;
			m_vecBulletObject.erase(m_vecBulletObject.begin() + i);
		}
	}
}

//胜利
void CGameObject::Victory()
{

	//通关;
	if (m_nRound == 5)
	{
		system("cls");
		CDrawObject::WriteChar(34, 24, "  恭喜你挑战完成! ", 7);	
		Sleep(3000);
		m_nRound = 1;
		Welcome();	
	}

	int nTemp = m_vecTankObject[0].GetScores();
	int nTemp2 = m_vecTankObject[1].GetScores();


	if (m_bDouble)
	{				 
		system("cls");
		CDrawObject::WriteChar(35, 22, "闯关成功!", 7);
		CDrawObject::WriteChar(34, 24, "玩家1得分为:", 7); CDrawObject::WriteInt(43, 24, nTemp, 6);
		CDrawObject::WriteChar(34, 26, "玩家2得分为:", 7); CDrawObject::WriteInt(43, 26, nTemp2, 6);
		Sleep(3000);
		ClearData();
	}
	else
	{
		system("cls");
		CDrawObject::WriteChar(35, 22, "闯关成功!", 7);
		CDrawObject::WriteChar(34, 24, "玩家1得分为:", 7); CDrawObject::WriteInt(43, 24, nTemp, 6);
		Sleep(3000);
		ClearData();
	}

	ClearData();

	if (m_nRound < 5)
	{
		m_nRound += 1;
	}
	StartGame();


}

//死亡结束
void CGameObject::GameOver()
{

	system("cls");
	CDrawObject::WriteChar(35, 22, "游戏结束", 7);
	int nTemp = m_vecTankObject[0].GetScores();
	int nTemp2 = m_vecTankObject[1].GetScores();
	
	if (m_bDouble)
	{
		CDrawObject::WriteChar(34, 24, "玩家1得分为:", 7); CDrawObject::WriteInt(43, 24, nTemp, 6);
		CDrawObject::WriteChar(34, 26, "玩家2得分为:", 7); CDrawObject::WriteInt(43, 26, nTemp2, 6);
		Sleep(3000);
		ClearData();						//清除数据
		m_nRound = 1;						//关卡重置
		Welcome();
	}
	else
	{
		CDrawObject::WriteChar(34, 24, "玩家1得分为:", 7); CDrawObject::WriteInt(43, 24, nTemp, 6);
		Sleep(3000);
		ClearData();						//清除数据
		m_nRound = 1;						//关卡重置
		Welcome();
		
	}


}



//清空数据
void CGameObject::ClearData()
{
	//数据清空;
	if (m_bDouble)
	{
		m_nEnemy = 20;
	}
	else
	{
		m_nEnemy = 10;
	}

	m_nMapObject = {};

	//清空坦克;
	m_vecTankObject.clear();
	//清空子弹;
	m_vecBulletObject.clear();

	return;

}

//绘制敌人数量
void CGameObject::DrawEnemy(int nRound, int nEnemy)
{
	CDrawObject::WriteInt(68, 3, nRound, 6);
	CDrawObject::WriteInt(68, 5, nEnemy, 6);
}
//保存游戏数据
void CGameObject::SaveData()
{
	m_bData = true;

	//打开文件;
	FILE *pFile;
	fopen_s(&pFile, "D:\\tank.temp", "wb");

	//写入文件;

	fwrite(&m_bData, sizeof(m_bData), 1, pFile);
	fwrite(&m_bDouble, sizeof(m_bDouble), 1, pFile);
	fwrite(&m_nRound, sizeof(m_nRound), 1, pFile);
	fwrite(&m_nEnemy, sizeof(m_nEnemy), 1, pFile);
	fwrite(&m_nMapObject, sizeof(m_nMapObject), 1, pFile);



	//存入坦克数量;
	m_nTank = m_vecTankObject.size();
	fwrite(&m_nTank, sizeof(m_nTank), 1, pFile);
	//循环写入坦克;
	for (int i = 0; i < m_nTank; i++)
	{
		fwrite(&m_vecTankObject[i], sizeof(CTankObject), 1, pFile);
	}



	//存入子弹数量;
	m_nBullet = m_vecBulletObject.size();
	fwrite(&m_nBullet, sizeof(m_nBullet), 1, pFile);
	//循环写入子弹;
	for (int i = 0; i < m_nBullet; i++)
	{
		fwrite(&m_vecBulletObject[i], sizeof(CBulletObject), 1, pFile);
	}

	fclose(pFile);

	m_bData = false;

	return;

}
//读取自定义游戏
void CGameObject::ReadGameMenu()
{

}
//读取游戏存档
void CGameObject::ReadData()
{
	//打开文件;
	FILE *pFile;
	errno_t err = fopen_s(&pFile, "D:\\tank.temp", "rb");
	
	//读取文件;
	fread(&m_bData, sizeof(m_bData), 1, pFile);
	fread(&m_bDouble, sizeof(m_bDouble), 1, pFile);
	fread(&m_nRound, sizeof(m_nRound), 1, pFile);
	fread(&m_nEnemy, sizeof(m_nEnemy), 1, pFile);
	fread(&m_nMapObject, sizeof(m_nMapObject), 1, pFile);



	//读取坦克数量;
	fread(&m_nTank, sizeof(m_nTank), 1, pFile);
	//循环读入坦克;
	for (int i = 0; i < m_nTank; i++)
	{
		CTankObject TankTemp;
		fread(&TankTemp, sizeof(CTankObject), 1, pFile);
		//修改地图指针;
		TankTemp.SetMapObject(&m_nMapObject);
		m_vecTankObject.push_back(TankTemp);
	}

	//读取子弹数量;
	fread(&m_nBullet, sizeof(m_nBullet), 1, pFile);
	//循环写入子弹;
	for (int i = 0; i < m_nBullet; i++)
	{
		CBulletObject BulletTemp;
		fread(&BulletTemp, sizeof(CBulletObject), 1, pFile);
		//修改地图指针;
		BulletTemp.SetMapObject(&m_nMapObject);
		m_vecBulletObject.push_back(BulletTemp);
	}

	//关闭文件;												
	fclose(pFile);


	//开始游戏;
	StartGame();
	return;
}

//初始化坦克
bool CGameObject::IniTank()
{
	//初始化玩家;
	CTankObject PlayerA(23, 47, UP, true, 10, &m_nMapObject);
	m_vecTankObject.push_back(PlayerA);

	CTankObject PlayerB(35, 47, UP, true, 11, &m_nMapObject);
	//玩家B默认GG!
	PlayerB.SetLevel(0);
	PlayerB.SetIsDie(false);
	m_vecTankObject.push_back(PlayerB);

	//初始化NPC;
	CTankObject NPC1(2, 2, DOWN, false, 12, &m_nMapObject);
	m_vecTankObject.push_back(NPC1);

	CTankObject NPC2(30, 2, DOWN, false, 13, &m_nMapObject);
	m_vecTankObject.push_back(NPC2);

	CTankObject NPC3(57, 2, DOWN, false, 14, &m_nMapObject);
	m_vecTankObject.push_back(NPC3);

	return true;
}


//设置控制台窗口信息
void CGameObject::SetWindowsInfo()
{
	system("title TankWar");
	system("mode con cols=150 lines=50");
}

//游戏开始界面
void CGameObject::Show()
{
	CDrawObject::WriteChar(5,6, "    _  _  _  _  _           _           _           _     _           _    _             _          _           _  _  _  _       ", 7);
	CDrawObject::WriteChar(5,7, "   (_)(_)(_)(_)(_)        _(_)_        (_) _       (_)   (_)       _ (_)  (_)           (_)       _(_)_        (_)(_)(_)(_) _    ", 7);
	CDrawObject::WriteChar(5,8, "         (_)            _(_) (_)_      (_)(_)_     (_)   (_)    _ (_)     (_)           (_)     _(_) (_)_      (_)         (_)   ", 7);
	CDrawObject::WriteChar(5,9, "         (_)          _(_)     (_)_    (_)  (_)_   (_)   (_) _ (_)        (_)     _     (_)   _(_)     (_)_    (_) _  _  _ (_)   ", 7);
	CDrawObject::WriteChar(5,10,"         (_)         (_) _  _  _ (_)   (_)    (_)_ (_)   (_)(_) _         (_)   _(_)_   (_)  (_) _  _  _ (_)   (_)(_)(_)(_)      ", 7);
	CDrawObject::WriteChar(5,11,"         (_)         (_)(_)(_)(_)(_)   (_)      (_)(_)   (_)   (_) _      (_)  (_) (_)  (_)  (_)(_)(_)(_)(_)   (_)   (_) _       ", 7);
	CDrawObject::WriteChar(5,12,"         (_)         (_)         (_)   (_)         (_)   (_)      (_) _   (_)_(_)   (_)_(_)  (_)         (_)   (_)      (_) _    ", 7);
	CDrawObject::WriteChar(5,13,"         (_)         (_)         (_)   (_)         (_)   (_)         (_)    (_)       (_)    (_)         (_)   (_)         (_)   ", 7);

	CDrawObject::WriteChar( 7,22,"■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,23,"■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,24,"■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,25,"■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,27,"          ■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,28,"          ■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,29,"          ■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,30,"          ■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,32,"■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,33,"■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,34,"■■■■  ■■■■", 4);
	CDrawObject::WriteChar( 7,35,"■■■■  ■■■■", 4);

	CDrawObject::WriteChar(54,22,"          ■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,23,"          ■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,24,"          ■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,25,"          ■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,27,"■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,28,"■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,29,"■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,30,"■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,32,"          ■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,33,"          ■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,34,"          ■■■■  ■■■■", 2);
	CDrawObject::WriteChar(54,35,"          ■■■■  ■■■■", 2);

	CDrawObject::WriteChar(34,24," 1  单人模式 ", 7);
	CDrawObject::WriteChar(34,26," 2  双人模式 ", 7);
	CDrawObject::WriteChar(34,28," 3  读取游戏 ", 7);
	CDrawObject::WriteChar(34,30," 4  自绘地图 ", 7);
	CDrawObject::WriteChar(34,32," 5  退出游戏 ", 7);
	CDrawObject::WriteChar(34,38,"请输入您的选择:", 6);
}

CMapObject.cpp

#include "CMapObject.h"
#include "CDrawObject.h"
#include "CTankObject.h"
#include 

typedef struct _MapNode
{
	char MapName[30];			//存储地图名
}MapNode;
MapNode array[20];				//存储地图目录
int m_nStage = 0;

CMapObject::CMapObject() {}
CMapObject::~CMapObject() {}

//设置地图中指定坐标的值
bool CMapObject::SetMapValue(int nPosX, int nPosY, int Value)
{
	if (nPosX < 0 || nPosX>59 || nPosY < 0 || nPosY>49)
	{
		return false;
	}
	m_nMap[nPosY][nPosX] = Value;
	return true;
}


//获取地图中指定坐标的值
int CMapObject::GetMapValue(int nPosX, int nPosY)
{
	if (nPosX < 0 || nPosX>59 || nPosY < 0 || nPosY>49)
	{
		return -1;
	}
	return m_nMap[nPosY][nPosX];
}


//初始化地图
bool CMapObject::IniMap()
{

	for (int i = 0; i < MAP_Y; i++)
	{
		for (int j = 0; j < MAP_X; j++)
		{
			//写入边框值;
			if (i == 0 || j == 0 || i == MAP_Y - 1 || j == MAP_X - 1 || j == 59)
			{
				m_nMap[i][j] = 边界;
			}
			//跳过非空的位置;
			else if (!m_nMap[i][j])
			{
				continue;
			}
			else
			{
				//其他填充0;
				m_nMap[i][j] = 空地;
			}

		}
	}

	return true;
}


//绘制地图
bool CMapObject::DrawMap()
{
	system("color 0A");
	system("cls");

	for (int i = 0; i < MAP_Y; i++)
	{
		for (int j = 0; j < MAP_X; j++)
		{
			//绘制障碍物;
			switch (m_nMap[i][j])
			{
			case 边界:
				CDrawObject::WriteChar(j, i, "□", 7);
				break;
			case 钢墙:
				CDrawObject::WriteChar(j, i, "■", 7);
				break;
			case 土墙:
				CDrawObject::WriteChar(j, i, "▓", 6);
				break;
			case 河:
				CDrawObject::WriteChar(j, i, "~", 9);
				break;
			case 丛林:
				CDrawObject::WriteChar(j, i, "※", 2);
				break;
			default:
				break;
			}

			//绘制基地
			if ((j > 27 && j < 31) && (i > 45 && i < 49))
			{
				CDrawObject::WriteChar(j, i, "★", 4);
				m_nMap[i][j] = 基地;
			}
		}
	}
	return true;
}




//自定义地图
bool CMapObject::DIYEditMap()
{

	//设置窗口信息;
	CGameObject cg;
	cg.SetWindowsInfo();
	//加载绘图信息;
	DIYMapInfo();

	HANDLE hiInput = GetStdHandle(STD_INPUT_HANDLE);
	INPUT_RECORD StcRecord = {};
	DWORD dwRead = 0;

	//重设接受模式;避免受cls影响;
	SetConsoleMode(hiInput, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
	while (true)
	{
		ReadConsoleInput(hiInput, &StcRecord, 1, &dwRead);
		//鼠标事件;
		if (StcRecord.EventType == MOUSE_EVENT)
		{
			if (MouseEventProc(StcRecord.Event.MouseEvent))
			{
				SaveMap();
				//设置窗口标题;
				SetConsoleTitleA("TankWar_cpp");
				return true;
			}
		}
		//键盘事件;
		if (StcRecord.EventType == KEY_EVENT)
		{
			KeyEventProc(StcRecord.Event.KeyEvent);
		}
	}
	return true;
}


//显示进行中的游戏信息
void CMapObject::DrawGanmeInfo()
{
	CDrawObject::WriteChar(62, 3, "关卡数:", 2);
	CDrawObject::WriteChar(62, 5, "敌人数:", 2);

	CDrawObject::WriteChar(62, 8, "玩家1分数:", 4);
	CDrawObject::WriteChar(62, 10, "玩家1生命:", 4);
	CDrawObject::WriteChar(62, 12, "玩家1等级:", 4);

	CDrawObject::WriteChar(62, 14, "玩家2分数:", 4);
	CDrawObject::WriteChar(62, 16, "玩家2生命:", 4);
	CDrawObject::WriteChar(62, 18, "玩家2等级:", 4);

	CDrawObject::WriteChar(62, 39, "玩家1移动:", 7);
	CDrawObject::WriteChar(61, 41, "W-上 A-下 S-左 D-右 发射-J", 7);
	CDrawObject::WriteChar(62, 43, "玩家2移动:", 7);
	CDrawObject::WriteChar(61, 45, "↑上 ↓下 ←左 →右 发射-0", 7);
	CDrawObject::WriteChar(62, 24, "P   游戏暂停", 4);
	CDrawObject::WriteChar(62, 26, "B   保存游戏;", 6);
	CDrawObject::WriteChar(62, 28, "Esc 退出游戏;", 6);
}

//绘制游戏分数
void CMapObject::DrawScore(vector& vecTank)
{
	//等级小于2,分数每增加1000,等级加1;
	if ((vecTank[0].GetScores()) > 0 &&
		(vecTank[0].GetScores()) % 1000 == 0 &&
		(vecTank[0].GetLevel()) < 2)
	{
		int nLevel = vecTank[0].GetLevel();
		nLevel += 1;
		vecTank[0].SetLevel(nLevel);
	}

	if ((vecTank[1].GetScores()) > 0 &&
		(vecTank[1].GetScores()) % 1000 == 0 &&
		(vecTank[1].GetLevel()) < 2)
	{
		int nLevel = vecTank[0].GetLevel();
		nLevel += 1;
		vecTank[0].SetLevel(nLevel);
	}


	CDrawObject::WriteInt(68, 8, vecTank[0].GetScores(), 2);
	CDrawObject::WriteInt(68, 12, vecTank[0].GetLevel(), 2);
														 
	CDrawObject::WriteInt(68, 14, vecTank[1].GetScores(),2);
	CDrawObject::WriteInt(68, 18, vecTank[1].GetLevel(), 2);


}





//绘制编辑地图右侧信息
void CMapObject::DIYMapInfo()
{
	if (m_nMap[0][0] == 0) {
		//绘制基础地图;
		IniMap();
	}

	DrawMap();

	//文字信息;
	CDrawObject::WriteChar(63, 5, "0  擦除", 7); 
	CDrawObject::WriteChar(63, 8, "1  钢墙", 7); CDrawObject::WriteChar(71, 8, "■", 7);
	CDrawObject::WriteChar(63, 11, "2  土墙", 7); CDrawObject::WriteChar(71, 11, "▓", 6);
	CDrawObject::WriteChar(63, 14, "3  丛林", 7); CDrawObject::WriteChar(71, 14, "※", 2);
	CDrawObject::WriteChar(63, 17, "4  河流", 7); CDrawObject::WriteChar(71, 17, "~", 9);


	CDrawObject::WriteChar(61, 22, "Esc退出;", 6);
	CDrawObject::WriteChar(61, 25, "双击鼠标左键保存退出", 6);

	return;
}


//控制台输出绘制地图坐标
void CMapObject::OutPutPos(int nPosX, int nPoxY)
{
	char posBuf[100] = { 0 };
	sprintf_s(posBuf, sizeof(posBuf), "x=%2d,y=%2d", nPosX / 2, nPoxY);
	CDrawObject::WriteChar(60, 1, posBuf, 6);
	return;
}


//鼠标处理事件
bool CMapObject::MouseEventProc(MOUSE_EVENT_RECORD StcMouse)
{
	switch (StcMouse.dwEventFlags)
	{
	case 0:
		MouseClick(StcMouse);
		break;
	case  DOUBLE_CLICK:
		return true;
		break;
	case MOUSE_MOVED:
		MouseMove(StcMouse);
		break;
	default:
		break;
	}

	OutPutPos(StcMouse.dwMousePosition.X, StcMouse.dwMousePosition.Y);

	return false;
}


//鼠标拖动事件
bool CMapObject::MouseMove(MOUSE_EVENT_RECORD &StcMouse)
{
	//左键拖动;
	if (StcMouse.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
	{
		//界定绘制范围;
		if (m_nMapVlue < 6 &&
			StcMouse.dwMousePosition.X < 118 &&
			StcMouse.dwMousePosition.X>1 &&
			StcMouse.dwMousePosition.Y>0 &&
			StcMouse.dwMousePosition.Y < 49)
		{
			//根据地图值绘制相应图形;
			switch (m_nMapVlue)
			{
			case 2:
				CDrawObject::WriteChar(StcMouse.dwMousePosition.X / 2, StcMouse.dwMousePosition.Y, "■", 7);
				break;
			case 3:
				CDrawObject::WriteChar(StcMouse.dwMousePosition.X / 2, StcMouse.dwMousePosition.Y, "▓", 6);
				break;
			case 4:
				CDrawObject::WriteChar(StcMouse.dwMousePosition.X / 2, StcMouse.dwMousePosition.Y, "※", 2);
				break;
			case 5:
					CDrawObject::WriteChar(StcMouse.dwMousePosition.X / 2, StcMouse.dwMousePosition.Y, "~", 9);
				break;
				//橡皮擦;
			case 0:
				CDrawObject::WriteChar(StcMouse.dwMousePosition.X / 2, StcMouse.dwMousePosition.Y, "  ");
				break;
			default:
				break;
			}
			//输出坐标;
			m_nMap[StcMouse.dwMousePosition.Y][StcMouse.dwMousePosition.X / 2] = m_nMapVlue;

		}
	}

	return true;
}


//鼠标点击事件
bool CMapObject::MouseClick(MOUSE_EVENT_RECORD &StcMouse)
{
	//获取XY坐标;
	int x = StcMouse.dwMousePosition.X;
	int y = StcMouse.dwMousePosition.Y;

	return false;
}


//键盘处理事件
bool CMapObject::KeyEventProc(KEY_EVENT_RECORD &StcKeyEvent)
{
	if (StcKeyEvent.bKeyDown)
	{
		switch (StcKeyEvent.wVirtualKeyCode)
		{
			//键盘上方的1,2,3,4,十六进制ASCII码值;
		case 0x31:
		case 0x32:
		case 0x33:
		case 0x34:
			m_nMapVlue = (StcKeyEvent.wVirtualKeyCode & 0x0F) + 1;
			break;
		case 0x30://键盘上方的0
			m_nMapVlue = 0;
			break;
		case 0x1B://Esc退出
		{
			CGameObject cGameobj;
			cGameobj.Welcome();
			return false;
		}
		break;
		default:
			break;
		}
	}
	return false;
}


//保存地图
void CMapObject::SaveMap()
{
	//读取之前存档
	FILE*cfFile;
	fopen_s(&cfFile, "D:\\MapName.txt", "r");
	fread(&NumberMap, sizeof(int), 1, cfFile);
	fread(array, sizeof(array[0]), NumberMap, cfFile);
	fclose(cfFile);

	//保存地图名,方便查找
	char tempname[30];
	char mapname[30] = "D:\\";
	system("cls");
	CDrawObject::WriteChar(30, 20, "请输入您要保存的地图名:", 6);
	scanf_s("%s", tempname, 30);
	strcat_s(tempname, 30, ".map");
	strcat_s(mapname, 30, tempname);
	printf("%s", mapname);
	strcpy_s(array[NumberMap].MapName, 30, mapname);		//拼接地图存档名
	NumberMap++;			//地图数量
	FILE*fFile;
	fopen_s(&fFile, "D:\\MapName.txt", "w+");
	fwrite(&NumberMap, sizeof(int), 1, fFile);
	fwrite(array, sizeof(array[0]), NumberMap, fFile);
	fclose(fFile);

	//保存地图
	FILE *pFile;
	fopen_s(&pFile, mapname, "wb");
	fwrite(m_nMap, sizeof(m_nMap), 1, pFile);	//将地图数组存入文件;
	fclose(pFile);
}
//读取地图
void CMapObject::ReadMap(int m_nRound)
{

	FILE *pFile;
	switch (m_nRound)
	{
	case 1:
	{
		fopen_s(&pFile, "D:\\0.map", "rb");
		//读取文件;
		fread(m_nMap, sizeof(m_nMap), 1, pFile);
		fclose(pFile);
		break;
	}
	case 2:
	{
		fopen_s(&pFile, "D:\\1.map", "rb");
		//读取文件;
		fread(m_nMap, sizeof(m_nMap), 1, pFile);
		fclose(pFile);
		break;
	}
	case 3:
	{
		fopen_s(&pFile, "D:\\2.map", "rb");
		//读取文件;
		fread(m_nMap, sizeof(m_nMap), 1, pFile);
		fclose(pFile);
		break;
	}
	case 4:
	{
		fopen_s(&pFile, "D:\\3.map", "rb");
		//读取文件;
		fread(m_nMap, sizeof(m_nMap), 1, pFile);
		fclose(pFile);
		break;
	}
	case 5:
	{
		fopen_s(&pFile, "D:\\4.map", "rb");
		//读取文件;
		fread(m_nMap, sizeof(m_nMap), 1, pFile);
		fclose(pFile);
		break;
	}
	default:
		break;
	}

	
}
void CMapObject::ReadSaveMap()
{

	FILE*cfFile;
	fopen_s(&cfFile, "D:\\MapName.txt", "r");
	fread(&NumberMap, sizeof(int), 1, cfFile);
	fread(array, sizeof(array[0]), NumberMap, cfFile);
	fclose(cfFile);
	system("cls");
	CDrawObject::WriteChar(20, 5, "", 2);

	for (int i = 0; i <= NumberMap; i++)
	{
		printf("\n");
		printf("                                        %s\n", array[i].MapName);
	}

	CDrawObject::WriteChar(40, 30, "",6);
	printf("请输入你要选择的地图:");
	char tempname[30];
	char Smapname[30] = "D:\\";
	scanf_s("%s", tempname, 30);
	strcat_s(tempname, 30, ".map");
	strcat_s(Smapname, 30, tempname);

	int temp = 0;
	for (int i = 0; i < NumberMap; i++)
	{
		if (strcmp(array[i].MapName, Smapname) == 0)
		{
			FILE *pFile;
			errno_t err = fopen_s(&pFile, Smapname, "rb");			fread(m_nMap, sizeof(m_nMap), 1, pFile);
			fclose(pFile);
		}
		else
			temp++;
	}
	if (temp == NumberMap)
	{	
		CDrawObject::WriteChar(40, 20, "您的输入有误:", 4);
		CDrawObject::WriteChar(48, 20, "", 4);
		printf("%s", Smapname);
		Sleep(3000);
		exit(0);
	}
}

CTankObject.cpp

#include "CTankObject.h"
#include "CDrawObject.h"
#include "CMapObject.h"
#include "CAStar.h"

#include 

//类外初始化静态成员;
const int  CTankObject::m_ColorNPC[3] = { 2,3,6 };
const int  CTankObject::m_TankSpeed[3] = { 100,75,50 };


const int  CTankObject::m_TankShape[4][3][3] =
{
	{//上
		{ 0,1,0 },
		{ 1,1,1 },
		{ 1,0,1 }
	},
	{//下
		{ 1,0,1 },
		{ 1,1,1 },
		{ 0,1,0 }
	},
	{//左
		{ 0,1,1 },
		{ 1,1,0 },
		{ 0,1,1 }
	},
	{//右
		{ 1,1,0 },
		{ 0,1,1 },
		{ 1,1,0 }
	}
};



//初始化坦克
CTankObject::CTankObject(int PosX, int PosY, int Dir, bool Group, int ID, CMapObject* Object) :
	m_nPosX(PosX), m_nPosY(PosY), m_nDir(Dir), m_bGroup(Group), m_nID(ID)
{
	m_nLevel = 1;
	m_bIsDie = true;
	m_pMapObject = Object;
	m_nSpeed = m_TankSpeed[m_nLevel];

}



CTankObject::~CTankObject()
{

}


//绘制坦克
bool CTankObject::DrawObject()
{
	//遍历坦克形状;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			if (m_TankShape[m_nDir][j][i])
			{

				int nTempX = m_nPosX + i - 1;
				int nTempY = m_nPosY + j - 1;

				//跳过草;
				if (m_pMapObject->GetMapValue(nTempX, nTempY) == 丛林 ||
					m_pMapObject->GetMapValue(nTempX, nTempY) == 河)
				{
					continue;
				}

				//绘制玩家坦克;
				if (m_bGroup)
				{
					CDrawObject::WriteChar(nTempX, nTempY, "■", 4);
					m_pMapObject->SetMapValue(nTempX, nTempY, m_nID);
				}
				//绘制敌军坦克;
				if (!m_bGroup)
				{
					CDrawObject::WriteChar(nTempX, nTempY, "■", m_ColorNPC[m_nLevel]);
					m_pMapObject->SetMapValue(nTempX, nTempY, m_nID);
				}
			}
		}
	}


	return true;
}



//擦除坦克
bool CTankObject::ClsObject()
{
	//遍历坦克形状;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			if (m_TankShape[m_nDir][j][i])
			{

				int nTempX = m_nPosX + i - 1;
				int nTempY = m_nPosY + j - 1;
				//跳过草;
				if (m_pMapObject->GetMapValue(nTempX, nTempY) == 丛林 ||
					m_pMapObject->GetMapValue(nTempX, nTempY) == 河)
				{
					continue;
				}
				//绘制玩家坦克;
				if (m_bGroup)
				{
					CDrawObject::WriteChar(nTempX, nTempY, "  ");
					m_pMapObject->SetMapValue(nTempX, nTempY, 空地);
				}
				if (!m_bGroup)
				{
					CDrawObject::WriteChar(nTempX, nTempY, "  ");
					m_pMapObject->SetMapValue(nTempX, nTempY, 空地);
				}
			}
		}
	}
	return true;
}


//移动玩家坦克
bool CTankObject::MoveTank(int nDir)
{
	//清除坦克;
	this->ClsObject();
	//建立临时坦克对象;
	CTankObject TankTemp = *this;
	//方向不同只转向;可以原地旋转;

	if (TankTemp.m_nDir != nDir)
	{
		TankTemp.m_nDir = nDir;
	}
	else
	{
		switch (nDir)
		{
		case UP:	TankTemp.m_nPosY--;	break;
		case DOWN:	TankTemp.m_nPosY++;	break;
		case LEFT:	TankTemp.m_nPosX--;	break;
		case RIGHT:	TankTemp.m_nPosX++;	break;
		}
	}
	//检测通过将临时对象赋值给当前坦克;
	if (TankTemp.TankCollision())
	{
		*this = TankTemp;
	}

	//重新绘制;
	this->DrawObject();

	return true;
}


//npc移动
bool CTankObject::MoveNpc(const vector& vecTank, vector& vecBullet)
{
	if (this->GetIsDie())
	{

		//清除坦克;
		this->ClsObject();

		//建立临时坦克对象;
		CTankObject TankTemp = *this;

		switch (TankTemp.m_nDir)
		{
		case UP:	TankTemp.m_nPosY--;	break;
		case DOWN:	TankTemp.m_nPosY++;	break;
		case LEFT:	TankTemp.m_nPosX--;	break;
		case RIGHT:	TankTemp.m_nPosX++;	break;
		}

		//检测通过将临时对象赋值给当前坦克;
		if (TankTemp.TankCollision())
		{
			*this = TankTemp;
		}
		else
		{
			TankTemp = *this;
			TankTemp.m_nDir = rand() % 4;
			*this = TankTemp;
		}



		this->NPCCount++;

		//2级坦克搜索;
		CAStar AstarObj;
		if (this->m_nLevel == 2 && AstarObj.Astar(m_pMapObject, *this, vecTank)
			&& this->NPCCount > (8 - this->m_nLevel * 2))
		{
			this->m_nDir = AstarObj.m_Path[0].NewDir;
			CBulletObject BulletObject(*this);
			vecBullet.push_back(BulletObject);
			this->NPCCount = 0;
		}
		//1级坦克搜索;
		if (this->m_nLevel > 0 && Search() &&
			this->NPCCount > (10 - this->m_nLevel * 2))
		{
			CBulletObject BulletObject(*this);
			vecBullet.push_back(BulletObject);
			this->NPCCount = 0;
		}
		//0级坦克发射或高级坦克未搜索到目标发射;
		else if (this->NPCCount > 15)
		{
			CBulletObject BulletObject(*this);
			vecBullet.push_back(BulletObject);
			this->NPCCount = 0;
		}

		//重新绘制;
		this->DrawObject();

		return true;
	}
	else
	{
		return false;
	}
}


//寻路
bool CTankObject::Search()
{

	//遍历搜寻;
	for (int i = 0; i < 50; i++)
	{
		//遍历Y;//发现后转向;
		if (m_pMapObject->GetMapValue(m_nPosX, i) == 10
			|| m_pMapObject->GetMapValue(m_nPosX, i) == 11)
		{
			if (i < m_nPosY)
			{
				this->m_nDir = UP;
				return true;
			}
			else if (i > m_nPosY)
			{
				this->m_nDir = DOWN;
				return true;
			}

		}

		//遍历X;//发现后转向;
		if (m_pMapObject->GetMapValue(i, m_nPosY) == 10
			|| m_pMapObject->GetMapValue(i, m_nPosY) == 11)
			if (i < m_nPosX)
			{
				this->m_nDir = LEFT;
				return true;
			}
			else if (i > m_nPosX)
			{
				this->m_nDir = RIGHT;
				return true;
			}

	}
	return false;
}



//坦克碰撞检测
bool CTankObject::TankCollision()
{
	//遍历坦克形状;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			//循环检测9个点; 检测6个点会存在转向失败问题;
			int nTempX = m_nPosX + i - 1;
			int nTempY = m_nPosY + j - 1;
			//任意一点不为空且不是自己的点返回失败;
			if (m_pMapObject->GetMapValue(nTempX, nTempY) != 0 &&
				m_pMapObject->GetMapValue(nTempX, nTempY) != (this->m_nID) &&
				m_pMapObject->GetMapValue(nTempX, nTempY) != 丛林)
			{
				return false;
			}

		}
	}
	//检测所有为空可以走;
	return true;
}

你可能感兴趣的:(c++,c语言)