C++所实现的一个坦克大战小游戏,代码略渣,可以供新手参考,实现了坦克的自动寻路,玩家的自定义地图等功能,读档和存档还可优化
链接: https://pan.baidu.com/s/15Wc7yEvdsZ9yN0zEiwjcdw 提取码: qu5c
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;
}