程序流程图

  • 根据流程图我把程序分位四部分:
  1. 第一部分:游戏设置初始化
    :设置窗口名称,大小
    :隐藏光标,切换输入法(控制台赶紧去输入法是中文的)
    :背景音乐设置
  2. 第二部分:游戏菜单设计,选择游戏模式
    :清屏
    :打印开机界面,游戏菜单
    :游戏模式选择(开始游戏,双人模式,自定义地图等等)
  3. 第三部分:游戏初始化
    :清屏
    :初始化随机数种子
    :根据模式初始化坦克
    :初始化子弹
    :初始化地图
    :打印屏幕
  4. 第四部分:游戏主循环
    :游戏胜负检测
    :移动子弹循环
    :移动AI坦克循环
    :AI < 4并且剩余AI数量>0, 创建新的AI, 一次只创建一个
    :AI发射子弹
    :接收键盘输入,控制我方坦克移动
    :检测我方坦克是否死亡,进行复活

先上结果吧


这是我的想法,因为刚开始学,代码分的比较乱,大家随意看看

  • 因为寻路算法不会写,我的AI比较智障,就只写了思路,大家看看就好
    1.数据Data.h和Data.cpp,主要写全局变量(地图),还有坦克结构体,子弹结构体
//Data.h
#pragma once#define MAPH 40     //地图高度
#define MAPW 40     //地图宽度
//地形
enum AREA
{空地,边界,土墙,钢墙,河流,草地,沙地
};
//方向
enum DIR
{UP,DOWN,LEFT,RIGHT
};
//游戏模式
enum OPTION
{开始游戏 = 1, 双人模式 , 用户地图 , 载入存档, 退出游戏
};
//颜色
enum COLOR
{黑色, 蓝色, 绿色, 浅绿色, 红色, 紫色, 黄色, 白色, 灰色,淡蓝色, 淡绿色, 淡浅绿色, 淡红色, 淡紫色, 淡黄色, 亮白色
};
//人物标志
enum FLAG
{玩家A = 10, 玩家B = 11, AI_1 = 20, AI_2 = 21, AI_3 = 22, AI_4 = 23, 食物_A = 30, 食物_B = 31
};
//计数器
enum COUNTER
{游戏速度,玩家A复活时间, 玩家B复活时间,AI复活时间,AI移动冷却
};
//游戏菜单结构体
typedef struct _MENU
{const UINT NUM = 7;   //菜单项数COORD Coord[7];   //菜单打印坐标char menu[7][50] ={"*************************************************","                     开始游戏                    ","                     双人模式                    ","                     用户地图                    ","                     载入存档                    ","                     退出游戏                    ","*************************************************"};
}MENU,*PMENU;
//坦克结构体
typedef struct _TANK
{DWORD         ID : 8;               //坦克ID(0-255)DWORD       Type : 2;               //坦克类型(0-3)0是玩家A,1是玩家B,2是普通AI,3是特殊AIDWORD      Model : 2;               //坦克图案模型(0-3)0是玩家,AI不能使用DWORD      Alive : 1;               //存活为1,死亡为0DWORD     Revive : 2;               //复活次数(0-3)DWORD  Direction : 2;               //方向(0-3)DWORD     Health : 8;               //生命值(255)     DWORD SpeedLevel : 2;               //速度等级(0-3)DWORD       color : 8;               //坦克颜色DWORD     Score : 24;             //坦克杀敌分数(玩家AB有效)DWORD   BulletCD : 5;               //坦克子弹CDCOORD        codself;               //中心坐标
}TANK, *PTANK;//子弹结构体
typedef struct _BULLET
{COORD       codself;                   //中心坐标DWORD  Direction : 2;                   //方向(4)DWORD     Damage : 6;                   //子弹伤害(64)DWORD      Exist : 1;                   //子弹存在与否的变量,1为存在,0不存在DWORD       Type : 1;                   //1为AI子弹,0为玩家子弹DWORD         ID : 6;                   //子弹ID(64)
}BULLET, *PBULLET;extern char g_MAP[40][40];
extern char g_TankMap[40][40];
extern DWORD g_counter[12];
//Data.cpp
#include "pch.h"//全局地图==>记录地形
char g_MAP[40][40] = { 0 };
//坦克坐标地图,0空地,100是玩家A,101是玩家B,200+num是AI
char g_TankMap[40][40] = { 0 };
DWORD g_counter[12] = { 1,1,1,1,1,1,1,1,1,1,1,1 };  //间隔计数器数组,用于控制速度

2.坦克类:坦克的创建,移动,清除等功能

#pragma once
#include "AStar.h"
class Tank
{
public:static UINT remain_AI;       //剩余AI(未出现)TANK tankData{};         //坦克属性
public:Tank();              ~Tank();void InitPlayer(DWORD type);                //初始化玩家void InitAI(DWORD type, DWORD id = 0);      //初始化AIvoid CreatePlayer();                     //创建玩家坦克void CreateAI();                            //创建AI坦克void Show();                                //显示坦克void Clear();                             //清除坦克bool GetPath(COORD end);                  //利用AStar算法获取最短路径void Move(DIR dire);                       //根据输入方向移动//void MoveAI(DIR dire);                      //移动AIvoid MoveToHome();                            //追踪敌方老巢void MoveToTank(COORD enemy);               //追踪敌方坦克void MoveRandom();                          //随机移动bool GoCheck();                               //通行检测bool PosCheck(COORD pos);                 //检测当前九宫格能否创建坦克void UpdateMapInfo(bool IsClear = false);   //在地图上更新坦克方位//void Collision();                         //碰撞检测
private:AStar Astar;                                //寻路算法COORD home;                                   //老家坐标char* tank_figure[4][3][4] =             //坦克图案模型{{{"  ■  ", "■  ■", "  ■■", "■■  "},{"■●■", "■●■", "■●  ", "  ●■"},{"■  ■", "  ▉  ", "  ■■", "■■  "}},{{"┏┃┓", "┏┳┓", "┏┳┓", "┏┳┓"},{"┣●┫", "┣●┫", "━●┫", "┣●━"},{"┗┻┛", "┗┃┛", "┗┻┛", "┗┻┛"}},{{"┏┃┓", "◢━◣", "┏┳◣", "◢┳┓"},{"┣●┫", "┣●┫", "━●┃", "┃●━"},{"◥━◤", "┗┃┛", "┗┻◤", "◥┻┛"}},{{"╔┃╗", "╔╦╗", "╔╦╗", "╔╦╗"},{"╠█╣", "╠█╣", "━█╣", "╠█━"},{"╚╩╝", "╚┃╝", "╚╩╝", "╚╩╝"}}};
};
//Tank.cpp
#include "pch.h"
#include "Tank.h"UINT Tank::remain_AI = 16;Tank::Tank()
{   home.X = 19;home.Y = 37;
}Tank::~Tank()
{
}
/********************************************************
函数功能:初始化玩家坦克
参数  :玩家类型0(A)1(B)
返回值 :无
*********************************************************/
void Tank::InitPlayer(DWORD type)
{tankData.Type = type;tankData.Model = 0;tankData.Alive = 1;tankData.Revive = 3;tankData.Direction = UP;tankData.Health = 64;tankData.SpeedLevel = 1;tankData.color = 紫色;tankData.BulletCD = 0;if (tankData.Type == 0)   //玩家A{tankData.codself.X = 14;tankData.codself.Y = 37;}else                   //玩家B{tankData.codself.X = 24;tankData.codself.Y = 37;}
}
/********************************************************
函数功能:初始化AI坦克
参数1 :AI类型
参数2 :AI编号
返回值 :无
*********************************************************/
void Tank::InitAI(DWORD type, DWORD id /*= 0*/)
{tankData.ID = id;tankData.Type = type;tankData.Model = rand() % 3 + 1;tankData.Alive = 0;tankData.Revive = 0;tankData.Direction = UP;tankData.Health = 64;tankData.SpeedLevel = 1;tankData.color = rand() % 5 + 4;tankData.BulletCD = 0;tankData.codself.X = rand() % 36 + 2;tankData.codself.Y = 2;
}
/********************************************************
函数功能:创建玩家坦克
参数1 :无
返回值 :无
*********************************************************/
void Tank::CreatePlayer()
{//玩家Aif (tankData.Type == 0 && tankData.Alive == 0 && tankData.Revive > 0){tankData.Alive = 1;tankData.Revive--;tankData.Direction = 0;tankData.Health = 64;tankData.SpeedLevel = 1;tankData.BulletCD = 0;tankData.codself.X = 14;tankData.codself.Y = 37;}//玩家Bif (tankData.Type == 1 && tankData.Alive == 0 && tankData.Revive > 0){tankData.Alive = 1;tankData.Revive--;tankData.Direction = 0;tankData.Health = 64;tankData.SpeedLevel = 1;tankData.BulletCD = 0;tankData.codself.X = 24;tankData.codself.Y = 37;}Show();
}
/********************************************************
函数功能:创建AI坦克
参数1 :无
返回值 :无
*********************************************************/
void Tank::CreateAI()
{remain_AI--;tankData.Alive = 1;tankData.Health = 64;tankData.SpeedLevel = 1;tankData.BulletCD = 0;tankData.Direction = rand() % 4;tankData.codself.X = rand() % 36 + 2;tankData.codself.Y = 2;while (!PosCheck(tankData.codself))      //有障碍物重置坐标{tankData.codself.X = rand() % 36 + 2;tankData.codself.Y = 2;}Show();
}/********************************************************
函数功能:画坦克(人机共用)
参数  :无
返回值 :无
*********************************************************/
void Tank::Show()
{if (!tankData.Alive)    //坦克死亡不打印return;char* (*tankF)[4] = tank_figure[tankData.Model];    //选择坦克图案for (int i = 0; i < 3; i++)     //打印坦克{if (g_MAP[tankData.codself.Y - 1 + i][tankData.codself.X - 1] != 草地)WriteChar(tankData.codself.X - 1, tankData.codself.Y - 1 + i, tankF[i][tankData.Direction], tankData.color);}//在地图上更新坦克方位UpdateMapInfo();
}
/********************************************************
函数功能:清除坦克(人机共用)
参数  :无
返回值 :无
*********************************************************/
void Tank::Clear()
{for (int i = 0; i < 3; i++)for (int j = 0; j < 3; j++) {           if (g_MAP[tankData.codself.Y + j - 1][tankData.codself.X + i - 1] == 空地)WriteChar(tankData.codself.X + i - 1, tankData.codself.Y + j - 1, "  ", 黑色);}//清除地图上的坦克方位UpdateMapInfo(true);
}//*******************************************************
//函数功能  :获取最短路径
//参数        :终点坐标
//返回值   :无
//*******************************************************
bool Tank::GetPath(COORD end)
{Astar.InitMapInfo((char*)g_MAP, MAPH, MAPW);Astar.InitCoordInfo(tankData.codself,end);if (Astar.FindPath()){Astar.GetPath();return true;}return false;
}
/********************************************************
函数功能:坦克移动函数
参数  :方向
返回值 :无
*********************************************************/
void Tank::Move(DIR dire)
{tankData.Direction =(DWORD)dire;if (!tankData.Alive){return;} Clear();if (GoCheck()){//检测坦克当前方向可通行switch (tankData.Direction){case UP:tankData.codself.Y--; break;case DOWN:tankData.codself.Y++; break;case LEFT:tankData.codself.X--; break;case RIGHT:tankData.codself.X++; break;}}Show();
}
/********************************************************
函数功能:AI锁定老巢移动
参数1 :无
返回值 :无
*********************************************************/
void Tank::MoveToHome()
{if (!GetPath(home))        //没有找到路径就随机移动{tankData.Direction = rand() % 4;Move((DIR)tankData.Direction);               //移动return;}if (Astar.m_Path.empty())       //路径为空,说明到达目的地,随机切换方向发射子弹{tankData.Direction = rand() % 3 + 1;Move((DIR)tankData.Direction);              //移动return;}if (rand() % 5)//坦克有五分之四的几率选择正确的方向{int nIndex = Astar.m_Path.size() - 1;       tankData.Direction = Astar.m_Path[nIndex].d;Move((DIR)tankData.Direction);}else{//坦克有五分之一的几率不动}
}
/********************************************************
函数功能:AI锁定敌方坦克移动
参数1 :敌方坦克坐标
返回值 :无
*********************************************************/
void Tank::MoveToTank(COORD enemy)
{if (GetPath(enemy))                                //获取路径{if (Astar.m_Path.empty())        //路径为空,说明到达目的地,随机切换方向发射子弹{tankData.Direction = rand() % 4;return;}int nIndex = Astar.m_Path.size() - 1;       tankData.Direction = Astar.m_Path[nIndex].d;//更新方向Move((DIR)tankData.Direction);               //移动return;}//没有找到路径就随机移动tankData.Direction = rand() % 4;Move((DIR)tankData.Direction);                //移动
}
/********************************************************
函数功能:AI随机移动
参数1 :无
返回值 :无
*********************************************************/
void Tank::MoveRandom()
{DWORD CurrentDire = tankData.Direction;       //当前方向//遇到障碍物重置方向if (!GoCheck()){while (tankData.Direction == CurrentDire){tankData.Direction = rand() % 4;}Move((DIR)tankData.Direction);               //移动return;}//有%10的概率重置方向if (rand() % 10 == 5){tankData.Direction = rand() % 4;}Move((DIR)tankData.Direction);               //移动
}/********************************************************
函数功能:坦克通行检测
参数1 :无
返回值 :返回true可通行,返回0阻挡
*********************************************************/
bool Tank::GoCheck()
{switch (tankData.Direction){                           //当前方向为空地、草地、沙地并且无坦克时可通行case UP:if ((g_MAP[tankData.codself.Y - 2][tankData.codself.X - 1] == 0 || g_MAP[tankData.codself.Y - 2][tankData.codself.X - 1] == 5 || g_MAP[tankData.codself.Y - 2][tankData.codself.X - 1] == 6) &&(g_MAP[tankData.codself.Y - 2][tankData.codself.X] == 0 || g_MAP[tankData.codself.Y - 2][tankData.codself.X] == 5 || g_MAP[tankData.codself.Y - 2][tankData.codself.X] == 6) &&(g_MAP[tankData.codself.Y - 2][tankData.codself.X + 1] == 0 || g_MAP[tankData.codself.Y - 2][tankData.codself.X + 1] == 5 || g_MAP[tankData.codself.Y - 2][tankData.codself.X + 1] == 6)&&(g_TankMap[tankData.codself.Y - 2][tankData.codself.X - 1] ==0 && g_TankMap[tankData.codself.Y - 2][tankData.codself.X] == 0 && g_TankMap[tankData.codself.Y - 2][tankData.codself.X + 1] == 0))return true;elsereturn false;case DOWN:if ((g_MAP[tankData.codself.Y + 2][tankData.codself.X - 1] == 0 || g_MAP[tankData.codself.Y + 2][tankData.codself.X - 1] == 5 || g_MAP[tankData.codself.Y + 2][tankData.codself.X - 1] == 6) &&(g_MAP[tankData.codself.Y + 2][tankData.codself.X] == 0 || g_MAP[tankData.codself.Y + 2][tankData.codself.X] == 5 || g_MAP[tankData.codself.Y + 2][tankData.codself.X] == 6) &&(g_MAP[tankData.codself.Y + 2][tankData.codself.X + 1] == 0 || g_MAP[tankData.codself.Y + 2][tankData.codself.X + 1] == 5 || g_MAP[tankData.codself.Y + 2][tankData.codself.X + 1] == 6)&&(g_TankMap[tankData.codself.Y + 2][tankData.codself.X - 1] == 0 && g_TankMap[tankData.codself.Y + 2][tankData.codself.X] == 0 && g_TankMap[tankData.codself.Y + 2][tankData.codself.X + 1] == 0))return true;elsereturn false;case LEFT:if ((g_MAP[tankData.codself.Y - 1][tankData.codself.X - 2] == 0 || g_MAP[tankData.codself.Y - 1][tankData.codself.X - 2] == 5 || g_MAP[tankData.codself.Y - 1][tankData.codself.X - 2] == 6) &&(g_MAP[tankData.codself.Y][tankData.codself.X - 2] == 0 || g_MAP[tankData.codself.Y][tankData.codself.X - 2] == 5 || g_MAP[tankData.codself.Y][tankData.codself.X - 2] == 6) &&(g_MAP[tankData.codself.Y + 1][tankData.codself.X - 2] == 0 || g_MAP[tankData.codself.Y + 1][tankData.codself.X - 2] == 5 || g_MAP[tankData.codself.Y + 1][tankData.codself.X - 2] == 6)&&(g_TankMap[tankData.codself.Y - 1][tankData.codself.X - 2] == 0 && g_TankMap[tankData.codself.Y ][tankData.codself.X-2] == 0 && g_TankMap[tankData.codself.Y +1][tankData.codself.X-2] == 0))return true;elsereturn false;case RIGHT:if ((g_MAP[tankData.codself.Y - 1][tankData.codself.X + 2] == 0 || g_MAP[tankData.codself.Y - 1][tankData.codself.X + 2] == 5 || g_MAP[tankData.codself.Y - 1][tankData.codself.X + 2] == 6) &&(g_MAP[tankData.codself.Y][tankData.codself.X + 2] == 0 || g_MAP[tankData.codself.Y][tankData.codself.X + 2] == 5 || g_MAP[tankData.codself.Y][tankData.codself.X + 2] == 6) &&(g_MAP[tankData.codself.Y + 1][tankData.codself.X + 2] == 0 || g_MAP[tankData.codself.Y + 1][tankData.codself.X + 2] == 5 || g_MAP[tankData.codself.Y + 1][tankData.codself.X + 2] == 6)&&(g_TankMap[tankData.codself.Y - 1][tankData.codself.X + 2] == 0 && g_TankMap[tankData.codself.Y][tankData.codself.X + 2] == 0 && g_TankMap[tankData.codself.Y + 1][tankData.codself.X + 2] == 0))return true;elsereturn false;default:return false;}
}
/********************************************************
函数功能:障碍物检测(人机共用)
参数1 :坦克中心坐标
返回值 :无障碍返回true
*********************************************************/
bool Tank::PosCheck(COORD pos)
{COORD tankCoord[9] = { 0 };tankCoord[0] = pos;//顶点坐标tankCoord[1].X = tankCoord[0].X - 1;        //左上顶点tankCoord[1].Y = tankCoord[0].Y - 1;tankCoord[2].X = tankCoord[0].X + 1;       //右上顶点tankCoord[2].Y = tankCoord[0].Y - 1;tankCoord[3].X = tankCoord[0].X - 1;        //左下顶点tankCoord[3].Y = tankCoord[0].Y + 1;tankCoord[4].X = tankCoord[0].X + 1;      //右下顶点tankCoord[4].Y = tankCoord[0].Y + 1;//四周坐标tankCoord[5].X = tankCoord[0].X;         //上tankCoord[5].Y = tankCoord[0].Y - 1;tankCoord[6].X = tankCoord[0].X;           //下tankCoord[6].Y = tankCoord[0].Y + 1;tankCoord[7].X = tankCoord[0].X - 1;      //左tankCoord[7].Y = tankCoord[0].Y;tankCoord[8].X = tankCoord[0].X + 1;      //右tankCoord[8].Y = tankCoord[0].Y;for (int i = 0; i < 9; i++){if (g_TankMap[tankCoord[i].Y][tankCoord[i].X] != 0 ||g_MAP[tankCoord[i].Y][tankCoord[i].X] != 0){return false;}}return true;
}void Tank::UpdateMapInfo(bool IsClear)
{COORD tankCoord[9] = { 0 };int tankType = 0;                     //地图坦克标志tankCoord[0] = tankData.codself;       //获取坦克坐标tankCoord[1].X = tankCoord[0].X - 1;       //左上顶点tankCoord[1].Y = tankCoord[0].Y - 1;tankCoord[2].X = tankCoord[0].X + 1;       //右上顶点tankCoord[2].Y = tankCoord[0].Y - 1;tankCoord[3].X = tankCoord[0].X - 1;        //左下顶点tankCoord[3].Y = tankCoord[0].Y + 1;tankCoord[4].X = tankCoord[0].X + 1;      //右下顶点tankCoord[4].Y = tankCoord[0].Y + 1;tankCoord[5].X = tankCoord[0].X;           //上tankCoord[5].Y = tankCoord[0].Y - 1;tankCoord[6].X = tankCoord[0].X;           //下tankCoord[6].Y = tankCoord[0].Y + 1;tankCoord[7].X = tankCoord[0].X - 1;      //左tankCoord[7].Y = tankCoord[0].Y;tankCoord[8].X = tankCoord[0].X + 1;      //右tankCoord[8].Y = tankCoord[0].Y;switch (tankData.Type)              //获取坦克类型{case 0:tankType = 10; break;      //玩家Acase 1:tankType = 11; break;      //玩家Bcase 2:tankType = 20 + tankData.ID; break;   //普通AIcase 3:tankType = 23; break;     //特殊AIdefault:break;}if (IsClear){for (int i = 0; i < 9; i++)     //清除坦克方位{g_TankMap[tankCoord[i].Y][tankCoord[i].X] = 0;}}else{for (int i = 0; i < 9; i++)        //更新坦克方位{g_TankMap[tankCoord[i].Y][tankCoord[i].X] = tankType;}}
}

3.子弹类:子弹的创建,移动,清除,碰撞检测

#pragma once
#include "Tank.h"class Bullet
{
public:BULLET Data = {};       //子弹属性结构体
public:Bullet();~Bullet();void CreateAI(Tank &tank);            //创建AI子弹void Create(Tank &tank);            //创建普通子弹void Move();                        //移动子弹bool Hit(Tank (&tank)[6]);            //子弹碰撞处理void Show();                        //打印子弹void Clear();                     //清除子弹bool GoCheck();                       //通行检测
private:};
//Bullet.cpp
#include "pch.h"
#include "Bullet.h"Bullet::Bullet()
{
}Bullet::~Bullet()
{
}
/********************************************************
函数功能:创建AI子弹
参数  :无
返回值 :无
*********************************************************/
void Bullet::CreateAI(Tank &tank)
{if (!(rand() % 10))        //冷却结束后在随后的每个游戏周期中有10分之一的可能发射子弹{Create(tank);}
}//************************************
// Method:    Create
// FullName:  Bullet::Create
// Access:    public
// Returns:   void
// Qualifier:
// Parameter: const Tank & tank
//************************************
void Bullet::Create(Tank &tank)
{//更新子弹信息-->|方向|存在状态|类型|坐标|伤害SHORT tankx = tank.tankData.codself.X;SHORT tanky = tank.tankData.codself.Y;Data.Damage = 32;Data.Direction = tank.tankData.Direction;          Data.Exist = 1;if(tank.tankData.Type==0 || tank.tankData.Type ==1)Data.Type = 0;elseData.Type = 1;switch (Data.Direction){case 0:Data.codself.X = tankx; Data.codself.Y= tanky - 2; break;case 1:Data.codself.X = tankx; Data.codself.Y = tanky + 2; break;case 2:Data.codself.X = tankx - 2; Data.codself.Y = tanky; break;case 3:Data.codself.X = tankx + 2; Data.codself.Y = tanky; break;}
}
/********************************************************
函数功能:子弹移动
参数  :无
返回值 :无
*********************************************************/
void Bullet::Move()
{           switch (Data.Direction)     {case UP:Data.codself.Y--; break;case DOWN:Data.codself.Y++; break;case LEFT:Data.codself.X--; break;case RIGHT:Data.codself.X++; break;}
}/********************************************************
函数功能:子弹碰撞函数
参数  :坦克对象数组
返回值 :正常返回0,炸毁老家返回1
*********************************************************/
bool Bullet::Hit(Tank(&tank)[6])
{SHORT X = Data.codself.X;SHORT Y = Data.codself.Y;//碰撞障碍物switch (g_MAP[Data.codself.Y][Data.codself.X]){//可正常通行case 沙地:case 河流:Show(); break;//隐藏通行:case 草地:break;//同归于尽,一次性打掉三块砖,方便坦克出行case 土墙:{Data.Exist = 0;if (Data.Direction == LEFT || Data.Direction == RIGHT)      //纵向删除三块土墙,非土墙忽略{for (int i = -1; i <= 1; i++){if (g_MAP[Data.codself.Y + i][Data.codself.X] == 土墙){g_MAP[Data.codself.Y + i][Data.codself.X] = 空地;WriteChar(Data.codself.X, Data.codself.Y + i, "  ", 0x00);}}}else{for (int i = -1; i <= 1; i++){if (g_MAP[Data.codself.Y][Data.codself.X + i] == 土墙){g_MAP[Data.codself.Y][Data.codself.X + i] = 空地;WriteChar(Data.codself.X + i, Data.codself.Y, "  ", 0x00);}}}break;}//自杀case 边界:case 钢墙:Data.Exist = 0; break;case 9:Data.Exist = 0;         //老巢炸毁WriteChar(18, 36, "      ", 0x0F);WriteChar(18, 37, "◢◣  ", 0x0F);WriteChar(18, 38, "███", 0x0F);return true;}if (g_TankMap[Y][X] != 0) //碰撞坦克{//子弹与友方坦克碰撞, 隐藏子弹, 不用处理//if (Data.Type == 0 && (g_TankMap[Y][X] == 10 || g_TankMap[Y][X] == 11) ||//  Data.Type == 1 && g_TankMap[Y][X] >= 20)//子弹与敌方坦克碰撞if (Data.Type == 1 && (g_TankMap[Y][X] == 10 || g_TankMap[Y][X] == 11) ||Data.Type == 0 && g_TankMap[Y][X] >= 20){Data.Exist = 0;      //子弹消失//获取坦克信息,坦克消失if (g_TankMap[Y][X] == 10){tank[0].tankData.Alive = 0;       //玩家A死亡tank[0].Clear();}if (g_TankMap[Y][X] == 11){tank[1].tankData.Alive = 0;       //玩家B死亡tank[1].Clear();}if (g_TankMap[Y][X] >= 20){int nIndex = g_TankMap[Y][X] % 20 + 2; //AI下标tank[nIndex].tankData.Alive = 0;tank[nIndex].Clear();tank[0].tankData.Score += 10;         //更新坦克得分分数//if (nIndex == 3)  //特殊坦克死亡会留下食物//{//  WriteChar(tank[3].tankData.codself.X, tank[3].tankData.codself.X, "卐", 黄色);// //更新地图标志//}}}}//与敌军子弹碰撞//if (Data.Type == 1 && g_TankMap[Y][X] == 1 || Data.Type == 0 && g_TankMap[Y][X] == 2)//{// Data.Exist = 0;//}return false;
}
/********************************************************
函数功能:打印子弹
参数  :子弹
返回值 :无
*********************************************************/
void Bullet::Show()
{if (Data.Exist)            //子弹存在{WriteChar(Data.codself.X, Data.codself.Y, "☉", 0x0A);//在g_TankMap更新子弹方位/*if (Data.Type)g_TankMap[Data.codself.Y][Data.codself.X] = 2;elseg_TankMap[Data.codself.Y][Data.codself.X] = 1;*/}
}
/********************************************************
函数功能:清除子弹
参数1 :无
返回值 :无
*********************************************************/
void Bullet::Clear()
{//如果该位置是坦克,不用清除if (g_TankMap[Data.codself.Y][Data.codself.X]){return;}switch (g_MAP[Data.codself.Y][Data.codself.X]){case 空地:WriteChar(Data.codself.X, Data.codself.Y, "  ", 0x0F); break;case 河流:WriteChar(Data.codself.X, Data.codself.Y, "~", 0x1F); break;case 沙地:WriteChar(Data.codself.X, Data.codself.Y, "▓", 0x06); break;default:break;}//在g_TankMap更新子弹方位//g_TankMap[Data.codself.Y][Data.codself.X] = 0;
}
/********************************************************
函数功能:子弹当前位置检测
参数  :无
返回值 :可通行返回true
*********************************************************/
bool Bullet::GoCheck()
{return (g_MAP[Data.codself.Y][Data.codself.X] == 空地 &&g_TankMap[Data.codself.Y][Data.codself.X] == 0);
}

4.AStar寻路算法类,AI锁定敌人移动算法

#pragma once/*********************************************************************************
AStar算法:openList:保存待检测的点closeList:保存已检测的点(包含最短路径)G Path:移动损耗(即从起点开始每走一步加1,斜走加根号2)H Path:离目的地距离F Path:F=G+H
**********************************************************************************/
class AStar
{
public:AStar();~AStar();//自定义的坐标结构体typedef struct _MY_COORD :public COORD{//重载等号运算符,方便比较bool operator==(COORD cod){return (X == cod.X) && (Y == cod.Y);}//重载赋值运算符,方便赋值void operator=(COORD cod){X = cod.X;Y = cod.Y;}short d; //坐标点方向}MY_COORD, *PMY_COORD;//节点的信息结构体typedef struct _NODE_INFO{int g;//移动损耗(每一动一次加1)int h;//距离终点最短距离int f;//g+hvoid SetH_F(COORD cod2){h = abs(codSelf.X - cod2.X) + abs(codSelf.Y - cod2.Y);f = g + h;}MY_COORD codSelf;  //自身坐标MY_COORD codParent;//父坐标点(由谁扩散出来的点的坐标)}NODE_INFO, *PNODE_INFO;private:void GetTankCoord(COORD tank);     //获取坦克九宫格坐标坐标vector<NODE_INFO> m_Open;  //代检测的点的集合vector<NODE_INFO> m_Close; //检测过的点(扩散过的点)的集合COORD m_tankCoord[4][4];            //坦克中心点坐标+当前方向三点坐标int m_Block;  //地图中的障碍物int m_MapH;   //地图高度int m_MapW;   //地图宽度char* m_pMap; //地图首地址COORD m_Start; //起点坐标COORD m_End;   //终点坐标bool m_bInitMapInfo;   //是否初始化地图信息bool m_bInitCoordInfo; //是否初始化起始坐标
public:void InitMapInfo(char* pMap, int nHigh, int nWidth);void InitCoordInfo(COORD codStart, COORD codEnd);void GetPath();  //获取最短路径bool FindPath(); //寻找包含最短路径的点//临时地图,保存该节点是否在open表或close中typedef struct _TEMP_MAP{char isOpen : 1;char isClose : 1;char recver : 6;}TEMP_MAP, *PTEMP_MAP;PTEMP_MAP m_pTempMap;      //临时地图vector<MY_COORD> m_Path;    //最短路径
};
//算法写的比较乱,没写好,这是思路:这是点到点的,坦克是九个点,得改装有点头疼
//bool FindPath(); //寻找包含最短路径的点
/*********************************************************************************寻路过程:1.初始化起点2.把起点添加到openList3.判断open是否为空(说明没找到)4.从oprn表中找到F最小值,进行扩散5.把扩散过的点,添加到close表中,并从open表中删除6.检测扩散出来的点是否存在终点,如果不是,就检测是否可以添加到open表中6.1.是否是终点(是,就直接返回true)6.2.是否越界6.3.是否是障碍物6.4.是否在open表中6.5.是否在close表中7.把检测合格的点添加到open表中8.重复3-7步**********************************************************************************/

5.游戏类:贴的不全,我的地图是40*40一行一行输的,太长

 void InitGameSet();             //初始化游戏设置void GameMenu();               //游戏主菜单void InitGame();             //初始化游戏void GameLoop();             //游戏主循环void GetMap(int level);          //获取关卡地图
private:bool SetWindowSize(TCHAR* pszWindowTitle, short x, short y);    //设置窗口大小void DrawMainScreen(char(*pMap)[40]);                           //画主屏幕地图void DrawSideScreen();                                          //打印副屏幕(游戏信息)void UpdateSideScreen();                                       //更新游戏信息void DrawUserSideScreen();                                      //自定义地图地形选择窗口void ClearMainScreen();                                            //清除主屏幕void ClearFullScreen();                                          //清除全屏COLOR SetColor(int No);                                           //设置字体颜色void MouseOp();                                                 //鼠标操作控制void GameStop();                                                //游戏暂停void GameOver(bool home);                                     //游戏结束void UserMap();                                                   //自定义地图void GameCheck();                                                //游戏胜负检测void MytankRebirth();                                           //复活玩家坦克void CreatBullet(Tank &tank);                                   //创建子弹void MoveBullet();                                                //移动子弹void KeyboardA();                                             //键盘输入控制void KeyboardB();                                               //控制玩家Bvoid SaveInfo();                                             //存档    void ReadInfo();                                                //读档void LoadRecord();                                              //加载存档信息void NextLevel();                                               //加载下一关卡
private:MENU menu;                          //游戏菜单UINT GameSpeed = 10;             //游戏速度bool SingleMode = true;              //单人模式标志UINT GameLevel = 1;                    //游戏关卡UINT MaxLevel = 3;                   //最大游戏关卡Tank tankArr[6];                    //坦克数组Tank& tankA = tankArr[0];            //玩家ATank& tankB = tankArr[1];         //玩家BTank* AItank = &tankArr[2];           //AIvector<Bullet> m_bullet;          //子弹    char obType = 0;                   //地形类型

#include "pch.h"
#include "Game.h"
#include <time.h>
#include <mmsystem.h>
#pragma comment(lib, "WINMM.LIB")Game::Game()
{}
Game::~Game()
{
}
/********************************************************
第一部分:初始化游戏设置1.设置窗口大小2.隐藏光标3.切换英文输入法4.背景音乐
*********************************************************/
void Game::InitGameSet()
{TCHAR* GameName = L"坦克大战";SetWindowSize(GameName, 120, 40);             //设置窗口标题,大小//切换输入法keybd_event(VK_SHIFT, 0, 0, 0);Sleep(100);keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);//隐藏光标HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);   //标准输出设备句柄CONSOLE_CURSOR_INFO cci;                          //鼠标结构体cci.dwSize = 1;cci.bVisible = false;SetConsoleCursorInfo(hStdOut, &cci);//设置背景音乐PlaySound(L"..\\TankDemo\\Sound\\tank.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);GetMap(GameLevel);        //地图初始化
}
/********************************************************
第二部分:游戏主菜单1.清屏2.打印游戏菜单3.模式选择控制
*********************************************************/
void Game::GameMenu()
{ClearFullScreen();     //清屏//初始化游戏菜单for (UINT i=0;i< menu.NUM;i++){menu.Coord[i].X = 16;}menu.Coord[0].Y = 20;menu.Coord[1].Y = 23;menu.Coord[2].Y = 25;menu.Coord[3].Y = 27;menu.Coord[4].Y = 29;menu.Coord[5].Y = 31;menu.Coord[6].Y = 34;//打印游戏菜单/****************************************************/char* Tank[8] ={{"          ★★█〓███████▇▅▅▅▅▅▅▅▄▄▄▄▄▅▇▇▇    ●    ●"},{"                         █●█"},{"       ◢▄██●★●█████●★●███▄◣"},{"     ◢〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓◣"},{"  ▄▅██████████████████████▅▄▃"},{"◢〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓◣"},{"◥███████████████████████████◤"},{"  ◥●▲●▲●▲●▲●▲●▲●▲●▲●▲●▲●▲●▲●◤"}};for (UINT i = 0; i < 8; i++){WriteChar(14, 2 + 2 * i, Tank[i], 0x02);}for (UINT i = 0; i < menu.NUM; i++){WriteChar(menu.Coord[i].X, menu.Coord[i].Y, menu.menu[i], 蓝色);}//游戏模式选择/****************************************************/WriteChar(menu.Coord[1].X, menu.Coord[1].Y, menu.menu[1], 红色); //默认选择第一项int No = 1;while (1){if (GetAsyncKeyState(VK_UP) & 0x8000)        //↑按键处理{WriteChar(menu.Coord[No].X, menu.Coord[No].Y, menu.menu[No], 蓝色);if (No == 1)No = 5;elseNo--;WriteChar(menu.Coord[No].X, menu.Coord[No].Y, menu.menu[No], 红色);}else if (GetAsyncKeyState(VK_DOWN) & 0x8000)//↓按键处理{WriteChar(menu.Coord[No].X, menu.Coord[No].Y, menu.menu[No], 蓝色);if (No == 5)No = 1;elseNo++;WriteChar(menu.Coord[No].X, menu.Coord[No].Y, menu.menu[No], 红色);}else if (GetAsyncKeyState(0xD) & 0x8000)      //回车确定{switch (No)                                  //进入游戏{case 开始游戏: SingleMode = true; return;case 双人模式: SingleMode = false; return;case 用户地图: UserMap(); return;case 载入存档: LoadRecord(); return;case 退出游戏: exit(0);}}Sleep(100);}
}
/********************************************************
函数功能:接收键盘输入,控制坦克
参数  :无
返回值 :无
*********************************************************/
void Game::KeyboardA()
{int nCount = 0;   //计数器if (GetAsyncKeyState('W') & 0x8000)tankA.Move(UP);else if (GetAsyncKeyState('S') & 0x8000)tankA.Move(DOWN);else if (GetAsyncKeyState('A') & 0x8000)tankA.Move(LEFT);else if (GetAsyncKeyState('D') & 0x8000)tankA.Move(RIGHT);else if (GetAsyncKeyState('J') & 0x8000){CreatBullet(tankA);}else if (GetAsyncKeyState(VK_SPACE) & 0x8000)   //空格{GameStop();} else if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)  // Esc键exit(0);else if (nCount++ % 5 == 0)      //防止按键粘连,达到微调速度{if (GameSpeed > 1 && GetAsyncKeyState(VK_ADD) & 0x8000)GameSpeed--;if (GameSpeed < 20 && GetAsyncKeyState(VK_SUBTRACT) & 0x8000)GameSpeed++;}                                   //退出程序函数    else{//return;}
}void Game::KeyboardB()
{if (GetAsyncKeyState(VK_UP) & 0x8000)tankB.Move(UP);else if (GetAsyncKeyState(VK_DOWN) & 0x8000)tankB.Move(DOWN);else if (GetAsyncKeyState(VK_LEFT) & 0x8000)tankB.Move(LEFT);else if (GetAsyncKeyState(VK_RIGHT) & 0x8000)tankB.Move(RIGHT);else if (GetAsyncKeyState(VK_NUMPAD5) & 0x8000){CreatBullet(tankB);}else{ }
}/********************************************************
函数功能:存档
参数  :无
返回值 :无
*********************************************************/
void Game::SaveInfo()
{FILE *fp;errno_t err;err = fopen_s(&fp, "..\\TankDemo\\GameInfo\\Info.txt", "wb");if (err){WriteChar(20, 20, "存档失败…",红色);return;}//保存地图fwrite(g_MAP, sizeof(char), 40 * 40, fp);//保存坦克fwrite(tankArr, sizeof(Tank), 6, fp);//保存子弹数量UINT bulletNum = m_bullet.size();fwrite(&bulletNum, sizeof(UINT), 1, fp);fwrite(&m_bullet, sizeof(vector<Bullet>), bulletNum, fp);//保存游戏信息-->|关卡|单人/双人模式标志|游戏速度fwrite(&GameLevel, sizeof(UINT), 1, fp);fwrite(&SingleMode, sizeof(bool), 1, fp);fwrite(&GameSpeed, sizeof(UINT), 1, fp);fclose(fp);
}
/********************************************************
函数功能:读档
参数  :无
返回值 :无
*********************************************************/
void Game::ReadInfo()
{FILE *fp;errno_t err;err = fopen_s(&fp, "..\\TankDemo\\GameInfo\\Info.txt", "rb");if (err){WriteChar(20, 20, "读档失败…", 红色);return;}//读取地图fread(g_MAP, sizeof(char), 40 * 40, fp);//读取坦克fread(tankArr, sizeof(Tank), 6, fp);//读取子弹/数量UINT bulletNum = 0;fread(&bulletNum, sizeof(UINT), 1, fp);fread(&m_bullet, sizeof(vector<Bullet>), bulletNum, fp);//读取游戏信息-->|关卡|单人/双人模式标志|游戏速度fread(&GameLevel, sizeof(UINT), 1, fp);fread(&SingleMode, sizeof(bool), 1, fp);fread(&GameSpeed, sizeof(UINT), 1, fp);fclose(fp);//初始化游戏DrawMainScreen(g_MAP);      //打印主屏幕DrawSideScreen();            //打印副屏幕for (UINT i = 0; i < 6; i++)           //打印坦克{tankArr[i].Show();}for (UINT i = 0; i < bulletNum; i++)    //打印子弹{m_bullet[i].Show();}
}
/********************************************************
函数功能:加载存档,进行游戏
参数  :无
返回值 :无
*********************************************************/
void Game::LoadRecord()
{//清屏ClearFullScreen();//初始化随机数种子srand((unsigned int)(time(NULL)));ReadInfo();GameLoop();
}
/********************************************************
函数功能:游戏胜利进入下一关
参数  :无
返回值 :无
*********************************************************/
void Game::NextLevel()
{int timing = 0, ColorNo = 1;COLOR Color;GameLevel++;if (GameLevel <= MaxLevel)while (1){if (timing++ % 30 == 0)        //30次打印一次{Color = SetColor(ColorNo);WriteChar(18, 20, "恭喜过关!", Color);     //主屏幕中心打印WriteChar(50, 15, "等待下关", Color);      //副屏幕打印WriteChar(45, 18, "请按回车键进入下一关卡!", Color);WriteChar(45, 19, "或按 Esc键退出游戏!", Color);if (++ColorNo == 8)ColorNo = 1;}if (GetAsyncKeyState(0xD) & 0x8000)  //回车键{WriteChar(50, 15, "正在进行", 0x01);         //清除副屏幕提示WriteChar(45, 18, "                       ", 0x00);WriteChar(45, 19, "                       ", 0x00);ClearMainScreen();           //主屏清屏函数GetMap(GameLevel);          //获取关卡地图InitGame();                 //从本关重新开始break;}else if (GetAsyncKeyState(0x1B) & 0x8000)  //Esc键退出 exit(0);Sleep(20);}else   // 通关while (1){if (timing++ % 5 == 0){Color = SetColor(ColorNo);WriteChar(18, 20, "恭喜通过全部关卡!", Color);     //主屏幕中心打印WriteChar(50, 15, "全部通关", Color);                //副屏幕打印WriteChar(45, 18, "恭喜通过全部关卡!", Color);WriteChar(45, 19, "按 Esc键退出游戏!", Color);if (++ColorNo == 8)ColorNo = 1;}if (GetAsyncKeyState(0x1B) & 0x8000)  //Esc键退出    exit(0);Sleep(20);}
}/********************************************************
函数功能:自定义地图副屏幕(地形选择)
参数  :无
返回值 :无
*********************************************************/
void Game::DrawUserSideScreen()
{for (int i = 0; i < 40; i++)for (int j = 0; j < 20; j++){switch (UserSideScreen[i][j]){case 1:WriteChar(j + 40, i, "■", 0x0F); break;case 2:WriteChar(j + 40, i, "▄ 土墙", 0x04); break;        //红色的土墙case 3:WriteChar(j + 40, i, "■ 钢墙", 0x0F); break;        //白色的钢墙case 4:WriteChar(j + 40, i, "~ 河流", 0x1F); break;        //蓝色的河流case 5:WriteChar(j + 40, i, "▓ 草地", 0x02); break;        //绿色的草地case 6:WriteChar(j + 40, i, "▓ 沙地", 0x06); break;        //黄色的沙地case 7:WriteChar(j + 40, i, "  保存地图", 0x09); break;     case 8:WriteChar(j + 40, i, "**", 0x0D); break;                    case 9:WriteChar(j + 40, i, "返回主菜单", 0x09); break;       }}
}
/********************************************************
函数功能:设置字体颜色
参数  :颜色编号
返回值 :颜色
*********************************************************/
COLOR Game::SetColor(int No)
{switch (No){case 0:return 黑色;case 1:return 蓝色;case 2:return 绿色;case 3:return 浅绿色;case 4:return 红色;case 5:return 紫色;case 6:return 黄色;case 7:return 白色;case 8:return 灰色;case 9:return 淡蓝色;case 10:return 淡绿色;case 11:return 淡浅绿色;case 12:return 淡红色;case 13:return 淡紫色;case 14:return 淡黄色;default:return 亮白色;};
}/********************************************************
函数功能:鼠标按键处理函数
参数  :无
返回值 :无
*********************************************************/
void Game::MouseOp()
{HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);INPUT_RECORD stcRecord = { 0 };     //定义输入事件结构体 MOUSE_EVENT_RECORD mer;    //鼠标事件DWORD dwRead = 0;          //用于存储读取记录  COORD pos = { 0 };         //用于存储鼠标当前位置 //重设接受模式;避免受cls影响;SetConsoleMode(hStdIn, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);while (1){//等待事件ReadConsoleInput(hStdIn, &stcRecord, 1, &dwRead);//处理事件if (stcRecord.EventType == MOUSE_EVENT){mer = stcRecord.Event.MouseEvent;if (mer.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED){ //鼠标左击,绘制障碍物if (mer.dwMousePosition.X / 2 >= 18 && mer.dwMousePosition.X / 2 <= 20 && mer.dwMousePosition.Y >= 36)//鼠标在在老巢范围内continue;if (mer.dwMousePosition.X / 2 >= 1 && mer.dwMousePosition.X / 2 <= 38 &&mer.dwMousePosition.Y >= 1 && mer.dwMousePosition.Y <= 38)        //鼠标在地图范围内    {switch (obType){case 土墙:WriteChar(mer.dwMousePosition.X / 2, mer.dwMousePosition.Y, "▄", 0x04); break;        //红色的土墙case 钢墙:WriteChar(mer.dwMousePosition.X / 2, mer.dwMousePosition.Y, "■", 0x0F); break;        //白色的钢墙case 河流:WriteChar(mer.dwMousePosition.X / 2, mer.dwMousePosition.Y, "~", 0x1F); break;        //蓝色的河流case 草地:WriteChar(mer.dwMousePosition.X / 2, mer.dwMousePosition.Y, "▓", 0x02); break;        //绿色的草地case 沙地:WriteChar(mer.dwMousePosition.X / 2, mer.dwMousePosition.Y, "▓", 0x06); break;        //黄色的沙地default:break;}//保存坐标obMap[mer.dwMousePosition.Y][mer.dwMousePosition.X / 2] = obType;}}if (mer.dwButtonState == RIGHTMOST_BUTTON_PRESSED){ //鼠标右击,读取信息int obymin = 3, obymax = 5;if (mer.dwMousePosition.X >= 46 * 2 && mer.dwMousePosition.X <= 52 * 2 &&mer.dwMousePosition.Y >= obymin && mer.dwMousePosition.Y <= obymax){obType = 土墙;}else if (mer.dwMousePosition.X >= 46 * 2 && mer.dwMousePosition.X <= 52 * 2 &&mer.dwMousePosition.Y >= obymin + 5 && mer.dwMousePosition.Y <= obymax + 5){obType = 钢墙;}else if (mer.dwMousePosition.X >= 46 * 2 && mer.dwMousePosition.X <= 52 * 2 &&mer.dwMousePosition.Y >= obymin + 10 && mer.dwMousePosition.Y <= obymax + 10){obType = 河流;}else if (mer.dwMousePosition.X >= 46 * 2 && mer.dwMousePosition.X <= 52 * 2 &&mer.dwMousePosition.Y >= obymin + 15 && mer.dwMousePosition.Y <= obymax + 15){obType = 草地;}else if (mer.dwMousePosition.X >= 46 * 2 && mer.dwMousePosition.X <= 52 * 2 &&mer.dwMousePosition.Y >= obymin + 20 && mer.dwMousePosition.Y <= obymax + 20){obType = 沙地;}else if (mer.dwMousePosition.X >= 46 * 2 && mer.dwMousePosition.X <= 52 * 2 &&mer.dwMousePosition.Y >= obymin + 25 && mer.dwMousePosition.Y <= obymax + 25){ //保存地图for (int i = 1; i < 39; i++)for (int j = 1; j < 39; j++){g_MAP[i][j] = obMap[i][j];}}else if (mer.dwMousePosition.X >= 46 * 2 && mer.dwMousePosition.X <= 52 * 2 &&mer.dwMousePosition.Y >= obymin + 30 && mer.dwMousePosition.Y <= obymax + 30){  //返回主菜单GameMenu();return;}else{obType = 空地;}}if (mer.dwEventFlags == MOUSE_MOVED){char szBuf[100] = { 0 };sprintf_s(szBuf, sizeof(szBuf), "x=%2d,y=%2d  ", mer.dwMousePosition.X / 2, mer.dwMousePosition.Y);SetConsoleTitleA(szBuf);}}}
}
/********************************************************
函数功能:游戏暂停处理
参数  :无
返回值 :无
*********************************************************/
void Game::GameStop()
{int counter = 0, No = 1;COLOR color;while (1){color = SetColor(No);if (counter++ % 30 == 0){WriteChar(50, 15, "游戏暂停", color);WriteChar(45, 18, "请按回车键继续游戏!", color);WriteChar(45, 19, "或按 Esc键退出游戏!", color);WriteChar(45, 20, "或按右Shift保存游戏!", color);if (++No == 8)No = 1;}if (GetAsyncKeyState(VK_RETURN) & 0x8000)     //回车键{          WriteChar(50, 15, "正在进行", 0x01);WriteChar(45, 18, "                     ", 0x00);WriteChar(45, 19, "                     ", 0x00);WriteChar(45, 20, "                     ", 0x00);break;}else if (GetAsyncKeyState(VK_RSHIFT) & 0x8000) //右Shift键保存{SaveInfo();    Sleep(1000);exit(0);        //保存玩退出游戏}else if (GetAsyncKeyState(0x1B) & 0x8000) //Esc键退出    exit(0);Sleep(100);}
}/********************************************************
第三部分:游戏初始化1.初始化随机数种子2.根据模式初始化坦克3.初始化子弹4.初始化地图5.初始化屏幕
*********************************************************/
void Game::InitGame()
{//清屏ClearFullScreen();//初始化随机数种子srand((unsigned int)(time(NULL)));//初始化坦克地图memset(g_TankMap, 0, sizeof(char) * 40 * 40);//初始化我的坦克复活次数tankA.InitPlayer(0);tankA.CreatePlayer();if (!SingleMode)         //双人游戏模式{tankB.InitPlayer(1);tankB.CreatePlayer();}//AI坦克初始化switch (GameLevel)      //根据关卡初始化AItank数量{case 1:AItank[0].remain_AI = 4; break;case 2:AItank[0].remain_AI = 8; break;case 3:AItank[0].remain_AI = 16; break;default:break;}         for(int i=0;i<3;i++)              {AItank[i].InitAI(2, i);}AItank[3].InitAI(3, 3);                    //创建特殊坦克AItank[0].CreateAI();AItank[1].CreateAI();//子弹清空if(!m_bullet.empty())m_bullet.clear();DrawMainScreen(g_MAP);        //打印主屏幕DrawSideScreen();            //打印副屏幕
}
/********************************************************
第四部分:游戏主循环1.游戏胜负检测2.移动子弹3.移动AI坦克4.AI < 4并且剩余AI数量>0, 创建新的AI, 一次只创建一个5.AI发射子弹6.接收键盘输入7.控制我方坦克8.我方坦克死亡, 复活(死亡瞬间复活, 不必放在主函数)
********************************************************/
void Game::GameLoop()
{while (1)                          //游戏主循环{if (g_counter[游戏速度]++%GameSpeed == 0){GameCheck();              //游戏胜负检测UpdateSideScreen();         //更新游戏信息            MoveBullet();               //移动子弹//移动AI坦克--四种AI坦克-->|锁定老巢|锁定玩家A|锁定玩家B|随机AI|         AItank[0].MoveToHome();AItank[1].MoveToTank(tankA.tankData.codself);if (!SingleMode){AItank[2].MoveToTank(tankB.tankData.codself);}else{AItank[2].MoveRandom();}AItank[3].MoveToTank(tankA.tankData.codself);//AI<4并且剩余AI数量>0,创建新的AI,一次只创建一个for (int i = 0; i < 4; i++){if (AItank[i].tankData.Alive == 0 && AItank[i].remain_AI > 0 &&g_counter[AI复活时间]++ % 90 == 0){ //如果坦克不存活。计时,每次建立有间隔1800msAItank[i].CreateAI();}}//AI发射子弹for (int i = 0; i < 4; i++){if (AItank[i].tankData.Alive && AItank[i].tankData.BulletCD == 10){CreatBullet(AItank[i]);AItank[i].tankData.BulletCD = 0;}else{AItank[i].tankData.BulletCD++;}}//接收键盘输入,控制我方坦克KeyboardA();KeyboardB();//我方坦克死亡,复活MytankRebirth();}Sleep(5);}
}
/********************************************************
函数功能:获取关卡地图
参数  :无
返回值 :无
*********************************************************/
void Game::GetMap(int level)
{int i, j;//int GameMap[3][40][40] =//我把数组删了,太长了for (i = 0; i < 40; i++)for (j = 0; j < 40; j++)g_MAP[i][j] = GameMap[level-1][i][j]; //获取关卡地图
}
/********************************************************
函数功能:创建子弹
参数  :坦克对象
返回值 :无
*********************************************************/
void Game::CreatBullet(Tank &tank)
{Bullet bullet = {};//判断是AI子弹还是玩家子弹if (tank.tankData.Type > 1 && !(rand()%11)){bullet.CreateAI(tank);}      elsebullet.Create(tank);//添加子弹,显示子弹m_bullet.push_back(bullet);int nIndex = m_bullet.size() - 1;    //添加子弹的下标if (nIndex < 0){cout << "子弹添加失败!" << endl;system("pause");return;}if (m_bullet[nIndex].GoCheck()){m_bullet[nIndex].Show();}else{    //判断子弹碰撞if (m_bullet[nIndex].Hit(tankArr)){GameOver(1);             //1表示老家炸毁}if (m_bullet[nIndex].Data.Exist == 0 )      //子弹碰撞消失{m_bullet.pop_back();}}
}
/********************************************************
函数功能:移动子弹
参数  :
返回值 :无
*********************************************************/
void Game::MoveBullet()
{bool Ret = false;for (UINT i = 0; i < m_bullet.size(); i++){        m_bullet[i].Clear();    //清除子弹m_bullet[i].Move();       //移动子弹if (m_bullet[i].GoCheck())    //检测障碍物{m_bullet[i].Show();     //正常通行}else{Ret = m_bullet[i].Hit(tankArr);    //碰撞处理if (Ret){GameOver(1);  //1表示老家炸毁}if (m_bullet[i].Data.Exist == 0 && m_bullet.size()>0)       //子弹碰撞消失{m_bullet.erase(m_bullet.begin() + i);}}}
}/********************************************************
函数功能:打印主屏幕地图
参数  :地图
返回值 :无
*********************************************************/
void Game::DrawMainScreen(char(*pMap)[40])
{for (int i = 0; i < 40; i++){for (int j = 0; j < 40; j++){switch (pMap[i][j]){case 边界:WriteChar(j, i, "■", 0x0F); break;        //白色的边界              case 土墙:WriteChar(j, i, "▄", 0x04); break;        //红色的土墙case 钢墙:WriteChar(j, i, "■", 0x0F); break;        //白色的钢墙case 河流:WriteChar(j, i, "~", 0x1F); break;        //蓝色的河流case 草地:WriteChar(j, i, "▓", 0x02); break;        //绿色的草地case 沙地:WriteChar(j, i, "▓", 0x06); break;        //黄色的沙地default: break;}}WriteChar(18, 36, "◣★◢", 0x0F);                     //老家WriteChar(18, 37, "███", 0x0F);                     //老家WriteChar(18, 38, "◢█◣", 0x0F);                     //老家}
}
/********************************************************
函数功能:清除主屏幕
参数  :无
返回值 :无
*********************************************************/
void Game::ClearMainScreen()
{for (int i = 1; i < 39; i++){WriteChar(1, i, "                                                \", 0x00);}
}
/********************************************************
函数功能:打印副屏幕
参数  :无
返回值 :无
*********************************************************/
void Game::DrawSideScreen()
{for (int i = 0; i < 40; i++){for (int j = 40; j < 60; j++){if (i == 0 || i == 39 || j == 59)WriteChar(j, i, "█", 0x0F);}}int basey = 2;WriteChar(47, basey, "第      关", 0x0F);WriteChar(46, basey + 3, "分  数: ", 0x0F);WriteChar(46, basey + 5, "生  命: ", 0x0F);WriteChar(46, basey + 7, "生  命: ", 0x0F);WriteChar(43, basey + 9, "剩余敌方坦克: ", 0x0F);WriteChar(43, basey + 11, "当前游戏速度: ", 0x0F);WriteChar(43, basey + 13, "当前游戏状态: ", 0x0F);WriteChar(40, basey + 15, "════════════════════", 0x01);WriteChar(48, basey + 21, "帮  助", 0x02);WriteChar(43, basey + 23, "坦克A: 方向键  w a s d ", 0x02);WriteChar(43, basey + 25, "     : 射击键  j 键 ", 0x02);WriteChar(43, basey + 27, "坦克B: 方向键  ←↑→↓", 0x02);WriteChar(43, basey + 29, "     : 射击键  5 键 ", 0x02);WriteChar(45, basey + 31, "+ - 调整游戏速度", 0x02);WriteChar(45, basey + 33, "空格键 暂停游戏", 0x02);WriteChar(45, basey + 35, "Esc键  退出游戏", 0x02);
}
/********************************************************
函数功能:更新游戏信息
参数1 :无
返回值 :无
*********************************************************/
void Game::UpdateSideScreen()
{int basey = 2;//清除上一次信息WriteChar(49, basey, "  ", 黑色);WriteChar(50, basey + 3, "   ", 黑色);WriteChar(50, basey + 5, "   ", 黑色);WriteChar(50, basey + 7, "   ", 黑色);WriteChar(50, basey + 9, "   ", 黑色);WriteChar(50, basey + 11, "   ", 黑色);//更新  WriteChar(49, basey, "", 黄色);printf("%d", GameLevel);               //游戏关卡WriteChar(50, basey + 3, "", 红色);printf("%d", tankA.tankData.Score + tankB.tankData.Score);//更新游戏分数WriteChar(50, basey + 5, "", 绿色);printf("%d", tankA.tankData.Revive);   //更新玩家A生命值(初始3条命)WriteChar(50, basey + 7, "", 绿色);printf("%d", tankB.tankData.Revive); //更新玩家B生命值WriteChar(50, basey + 9, "", 红色);printf("%d", tankA.remain_AI);          //剩余AI数WriteChar(50, basey + 11, "", 黄色);printf("%d", 21-GameSpeed);               //游戏速度WriteChar(50, basey + 13, "正在进行", 黄色); //游戏状态
}/********************************************************
函数功能:设置窗口信息
参数1 :窗口名称
参数2 :窗口宽度
参数3 :窗口高度
返回值 :成功返回真
*********************************************************/
bool Game::SetWindowSize(TCHAR* pszWindowTitle, short x, short y)
{HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTitle(pszWindowTitle);                  //设置窗口名称//获取最大控制台窗口大小COORD pos = GetLargestConsoleWindowSize(hStdOut);COORD BuffSize = { pos.X + 1,pos.Y + 1 };//设置控制台缓冲区大小if (!SetConsoleScreenBufferSize(hStdOut, BuffSize)){    //设置失败printf("buffer err(%d,%d)%d\n", BuffSize.X, BuffSize.Y, GetLastError());return false;}SMALL_RECT srctWindow = { 0,0,x,y };             //矩形,保存左上角坐标和右下角坐标if (!SetConsoleWindowInfo(hStdOut, true, &srctWindow)){   //设置控制台窗口大小失败printf("size err%d\n", GetLastError());return false;}//设置控制台缓冲区大小COORD Buff = { x + 1,y + 1 };if (!SetConsoleScreenBufferSize(hStdOut, Buff)){    //设置失败printf("buffer err(%d,%d)%d\n", Buff.X, Buff.Y, GetLastError());return false;}return true;
}/********************************************************
函数功能:游戏结束处理
参数  :0:我方死光1:老家炸毁
返回值 :无
*********************************************************/
void Game::GameOver(bool home)
{int timing = 0, ColorNo = 1;COLOR Color;while (1){if (timing++ % 30 == 0)        //30次打印一次{Color = SetColor(ColorNo);if(home){WriteChar(18, 20, "老家炸毁!", Color);     //主屏幕中心打印}WriteChar(18, 21, "游戏结束!", Color);         //主屏幕中心打印WriteChar(50, 15, "游戏结束!", Color);         //副屏幕打印WriteChar(45, 18, "请按回车键继续游戏!", Color); WriteChar(45, 19, "或按 Esc键退出游戏!", Color);if (++ColorNo == 8)ColorNo = 1;}if (GetAsyncKeyState(0xD) & 0x8000)  //回车键{ClearMainScreen();          //主屏清屏函数GetMap(GameLevel);          //获取关卡地图InitGame();                 //从本关重新开始break;}if (GetAsyncKeyState(0x1B) & 0x8000)  //Esc键退出  exit(0);Sleep(20);}
}/********************************************************
函数功能:用户自定义地图
参数1 :无
返回值 :无
*********************************************************/
void Game::UserMap()
{ClearFullScreen();             //清屏DrawMainScreen(obMap);          //打印主屏幕DrawUserSideScreen();            //打印副屏幕MouseOp();                       //鼠标操作处理
}
/********************************************************
函数功能:游戏胜负检测
参数  :无
返回值 :无
*********************************************************/
void Game::GameCheck()
{//胜利条件:AI坦克死光//AItank死光,胜利if (tankA.remain_AI == 0 && AItank[0].tankData.Alive == 0 && AItank[1].tankData.Alive == 0 &&AItank[2].tankData.Alive == 0 && AItank[3].tankData.Alive == 0){NextLevel();}//胜利处理函数//失败条件:我方坦克死光或者老家炸毁(老家炸毁瞬间调用GameOver函数,在这不做判断)if (SingleMode)        //单人模式  {if (tankA.tankData.Revive == 0 && tankA.tankData.Alive == 0)GameOver(0);       }else{if (tankA.tankData.Revive == 0 && tankA.tankData.Alive == 0 && tankB.tankData.Revive == 0 && tankB.tankData.Alive == 0)GameOver(0);   }
}
/********************************************************
函数功能:清屏函数(全屏)
参数  :无
返回值 :无
*********************************************************/
void Game::ClearFullScreen()
{for (int i = 0; i < 40; i++){WriteChar(0, i, "                                                           \", 0x00);}
}
/********************************************************
函数功能:玩家坦克复活
参数  :无
返回值 :无
*********************************************************/
void Game::MytankRebirth()
{if (SingleMode)        //单人模式{while (1){if (tankA.tankData.Alive == 0 && g_counter[玩家A复活时间]++ % 10 == 0)     //复活时间1stankA.CreatePlayer();elsereturn;Sleep(100);}}else{      //双人模式while (1){if (tankA.tankData.Alive == 0 && g_counter[玩家A复活时间]++ % 10 == 0)      //复活时间1stankA.CreatePlayer();else if (tankB.tankData.Alive == 0 && g_counter[玩家B复活时间]++ % 10 == 0)tankB.CreatePlayer();elsereturn;Sleep(100);}}
}

C++坦克大战(新手)相关推荐

  1. C++实现坦克大战(新手思路)

    C++实现坦克大战(新手思路) 第一次写,写的不好,还请多多包涵,本人也是第一次学习C++,因为在15派学习原因才接触到这个,本文仅仅提供我个人的一个思路. 效果图 项目实现的功能 实现的功能: 坦克 ...

  2. java画好看坦克_坦克大战第一节——画出自己的坦克(新手篇)

    刚刚开始学习java,对java不是很熟悉,但是自己的兴趣挺喜欢java.现在自己在自学java做一个小游戏,坦克大战. 自己现在完成了画出自己的坦克和坦克的移动方向.希望各位大神指导一下我这个刚刚学 ...

  3. 坦克大战第一节——画出自己的坦克(新手篇)

    刚刚开始学习Java,对Java不是很熟悉,但是自己的兴趣挺喜欢Java.现在自己在自学Java做一个小游戏,坦克大战. 自己现在完成了画出自己的坦克和坦克的移动方向.希望各位大神指导一下我这个刚刚学 ...

  4. C/C++游戏项目完整教程:《坦克大战》

    <坦克大战>以二战坦克为题材,既保留了射击类游戏的操作性,也改进了射击类游戏太过于复杂难玩的高门槛特点,集休闲与竞技于一身.经典再度袭来,流畅的画面,疯狂的战斗,让玩家再次进入疯狂坦克的世 ...

  5. Java游戏项目之坦克大战

    不知不觉已经更新到第五款游戏制作了,相信大家对游戏制作也是越来越熟练,让我们趁热打铁,继续了解第五款游戏--<坦克大战>. <坦克大战>是由日本南梦宫Namco游戏公司于198 ...

  6. java坦克大战爆炸效果_Java极致毁童年系列、你们火星的坦克大战这样的吧

    原标题:Java极致毁童年系列.你们火星的坦克大战这样的吧 这是使用java开发的一个单机版的小游戏 (未使用任何游戏引擎) 和经典版的坦克大战有些不同, 这里是纯坦克之间的战争, 英雄坦克并不用保护 ...

  7. 有没有被坦克大战支配过?

    在非智能机的时代,相信大家用直板机玩过各种各样的小游戏,如坦克大战.魂斗罗,那这个图标,大家一定见过 [Java游戏项目:源码+课件]编程的快乐大概就是 那个自己动手实现自己的的梦想游戏吧--手把手教 ...

  8. Java项目开发—坦克大战(附源码)

    今天给小伙伴们分享一个坦克大战游戏的详细编写流程,即使你是刚入门java的新手,只要你简单掌握了该游戏所需要的javase基础知识,便可以跟随教程视频完成属于你自己的坦克大战游戏!同时还可以加深和巩固 ...

  9. Java项目-坦克大战(附源码+文档)

    今天给小伙伴们分享一个坦克大战游戏的详细编写流程,即使你是刚入门java的新手,只要你简单掌握了该游戏所需要的javase基础知识,便可以跟随教程视频完成属于你自己的坦克大战游戏!同时还可以加深和巩固 ...

最新文章

  1. 我从GitHub上看到了编程语言八年变迁史 | Reddit 30.7k
  2. python自学平台-怎么自学python,大概要多久?
  3. Oracle 9i默认表空间
  4. oracle buffer block,8 Oracle深度学习笔记——BUFFER CACHE深入一
  5. 面向对象--内部属性类型
  6. endnote初始化数据库支持_服务端编程——数据库(MySQL、sequelize) - 天生笑点低你奈我何...
  7. nginx是干嘛用的_nginx小技巧 -非root身份运行nginx
  8. android点击下拉历史记录,uni-app,社交应用中,聊天页面下拉onPullDownRefresh获取历史消息,数据合并之后,滚动到下拉之前的位置,页面看不见闪动,完美解决...
  9. ONNX系列四 --- 使用ONNX使TensorFlow模型可移植
  10. c#特性 java注解,Java注解全面了解
  11. 使用 entrySet 遍历 Map 类集合 KV ,而不是 keySet 方式进行遍历的好处
  12. [Windows Phone] 如何在 Windows Phone 应用程式制作市集搜寻
  13. try,catch,finally
  14. 2021全国大学生数学建模竞赛报名通知+试题+优秀论文
  15. SQLServer安装时哪些功能是必需的(sql server 2016安装时选择哪些功能)
  16. UniApp设置APP图标配置,不自动生成所有图标问题
  17. 解决“the security certificate for this site has been revoked.the site should not be trusted.”
  18. 上海域格ASR和高通模块 USB端口分配及Linux下拨号说明
  19. 何谓OTA(Over-the-air programming)?
  20. c语言编写f16仿真程序,想学习一下 用C语言开发PIC的F16和F18系列单片机, 结果让IDE开发环境给搞悲剧,巨难用,...

热门文章

  1. 【机器学习入门基础】Matrix
  2. (27)STM32——光敏传感器实验笔记
  3. Flink-Task、SubTask、并行度
  4. 软件测试工程师常见面试题
  5. 小度机器人小胖机器人_小度机器人怎么升级?智能机器人百小度快速升级全攻略[多图]...
  6. Storm Trident 详细介绍
  7. png 微软ppt 透明度,教你一招永久搞定PPT导出高清图片的小技巧
  8. 厦大的计算机博士好考吗,厦大明年博士生招生七成以上不要初试 “考霸”没优势...
  9. 上周热点回顾(8.25-8.31)
  10. python中级11面向对象中