C++实现坦克大战(新手思路)
第一次写,写的不好,还请多多包涵,本人也是第一次学习C++,因为在15派学习原因才接触到这个,本文仅仅提供我个人的一个思路。
效果图
项目实现的功能
实现的功能:
坦克可以随意移动 可以发射炮弹 炮弹发射后自己向前移动
坦克移动的时有碰撞检测,可以被建筑物挡住
检测 坦克和障碍物 坦克和炮弹 炮弹和炮弹的碰撞
多种地形(河流,草丛 土墙 铁墙)
炮弹发射可以摧毁一部分地形
有简单的地图 有敌军随机移动
有双人模式 计分系统 自定义地图
多种敌军(在显示要区分) 读档存档 具有关卡概念
项目设计:
1.这个项目我设计了四个类:地图 坦克 游戏 子弹 还有一个所有类都要工具的函数(这里也可以建个类然后继承这个类)
地图 我采用双地图 一张静态地图存储不会动的障碍物 一张静态地图存储子弹和坦克这些会动的
坦克 要用类型区分坦克的属性,移动 碰撞 的方法
子弹 同样也是这样,子弹可以重载两个运算符(=,==)一个是初始化子弹用,一个子弹碰撞坦克使用
游戏类 操作坦克类对象和子弹类对象
上代码
地图类
cpp#pragma once
#include"工具.h"
class CMap
{
public:
//静态地图
bool SetMapValue(int nPox, int nPoY,int nValue);
int GetMapValue(int nPox, int nPoY);
//动态地图
bool SetDMapValue(int nPox, int nPoY, int nValue);
int GetDMapValue(int nPox, int nPoY);
//画边界
bool DrawMap();
//画草
void DRAWgrass();
//画河流
void DrawRiver();
//画墙
void DrawWall();
//画堡垒
void DrawFortress();
private:
int m_nMap[Mapx][Mapy] = {}; //静态地图
int m_dMap[Mapx][Mapy] = {}; //动态地图
};
//上面是.h的文件 下面是.cpp的文件
#include "CMap.h"
//修改动态地图上的地标
bool CMap::SetDMapValue(int nPox, int nPoY, int nValue)
{
m_dMap[nPox][nPoY] = nValue;
return true;
}
//修改静态地图上的地标
bool CMap::SetMapValue(int nPox, int nPoY, int nValue)
{
m_nMap[nPox][nPoY] = nValue;
return true;
}
//获得动态地图上的地标
int CMap::GetDMapValue(int nPox, int nPoY)
{
return m_dMap[nPox][nPoY];
}
//获得静态地图上的地标
int CMap::GetMapValue(int nPox, int nPoY)
{
return m_nMap[nPox][nPoY];
}
//画地图
bool CMap::DrawMap()
{
for (int i = 0;i < Mapx;i++)
{
for (int j = 0;j < Mapy;j++)
{
if (i == 0 || j == 0 || i == Mapx-1 || j == Mapy-1)
{
SetMapValue(i,j,边界);
writeChar(i, j, "■",15);
}
else
{
SetMapValue(i, j, 空地);
}
}
}
return true;
}
//画草
void CMap::DRAWgrass()
{
for (int j = 19;j < 23;j++)
{
for (int i = 1;i < 11;i++)
{
SetMapValue(i, j, 丛林);
writeChar(i, j, "WW", 2);
}
for (int i = 30;i < 39;i++)
{
SetMapValue(i, j, 丛林);
writeChar(i, j, "WW", 2);
}
}
}
//画河流
void CMap::DrawRiver()
{
for (int j = 10;j < 13;j++)
{
for (int i = 1;i < 11;i++)
{
SetMapValue(i, j, 河流);
writeChar(i, j, "~~", 1);
}
for (int i = 30;i < 39;i++)
{
SetMapValue(i, j, 河流);
writeChar(i, j, "~~", 1);
}
}
}
//画墙
void CMap::DrawWall()
{
for (int j = 16;j < 18;j++)
{
for (int i = 14;i < 26;i++)
{
SetMapValue(i, j, 边界);
writeChar(i, j, "■", 15);
}
}
}
//画堡垒
void CMap::DrawFortress()
{
for (int j = 36;j < 39;j++)
{
for (int i = 19;i < 22;i++)
{
SetMapValue(i, j, 木墙);
writeChar(i, j, "□", 6);
}
}
writeChar(20, 38, "◆", 4);
SetMapValue(20, 38, 老鹰);
}
坦克类
#pragma once
#include"CBullet.h"
#include"CMap.h"
#include<Windows.h>
#include<vector>
using std::vector;
class CMap;
enum Dir
{
UP=119, DOWN=115, LEFT=97, RIGHT=100
};
class CTank
{
public:
CBullet Bullet;
public:
//初始化玩家坦克
void CTankINFO(int type);
//初始化AI坦克
void AICTankINFO(int type,int num);
//擦坦克
void ClsTank(CTank Tank, CMap& map);
//画坦克
void DrawTank(CTank Tank, CMap& map);
//坦克移动
void MoveTank(CTank& Tank, CMap& map, vector<CTank*> CTanklist);
//AI坦克移动
void MoveAITank(CTank& Tank, CMap& map);
//坦克的碰撞
int TankCollision(CTank Tank,int dir,CMap &map);
//坦克的保存
void SaveCTank(vector<CTank*> CTanklist, CMap& map);
//坦克接口
Dir GetDIR();
int GetAlignment();
int GetPosX();
int GetPosY();
int Getbool();
int Getlive();
void Setbool(int n);
void Setlive(int n);
public:
bool m_Live; //坦克是否存活
int m_Alignment;//坦克的阵营
int m_PosX;
int m_PosY; //坦克坐标
Dir m_Dir; //坦克方向
int m_Type; //坦克类型
int m_Blood; //坦克血量
int m_Scores; //坦克杀敌分数
int m_TSpeed; //坦克速度
int m_TPast; //坦克的时钟
int m_Num; //坦克序号
int m_color; //坦克颜色
};
//上面是.h的文件 下面是.cpp的文件
#include"工具.h"
#include "CTank.h"
#include<time.h>
//TAnk的接口
Dir CTank::GetDIR()
{
return m_Dir;
}
int CTank::GetAlignment()
{
return m_Alignment;
}
int CTank::GetPosX()
{
return m_PosX;
}
int CTank::GetPosY()
{
return m_PosY;
}
int CTank::Getbool()
{
return m_Blood;
}
int CTank::Getlive()
{
return m_Live;
}
void CTank::Setbool(int n)
{
m_Blood = n;
}
void CTank::Setlive(int n)
{
m_Live = n;
}
//画坦克
void CTank::DrawTank(CTank Tank, CMap& map)
{
int x = Tank.m_PosX;
int y = Tank.m_PosY;
switch (Tank.m_Dir)
{
case UP:
{
writeChar(x - 1, y - 1, " ■ ", Tank.m_color);
writeChar(x - 1, y, "■■■", Tank.m_color);
writeChar(x - 1, y + 1, "■ ■", Tank.m_color);
}break;
case DOWN:
writeChar(x - 1, y - 1, "■ ■", Tank.m_color);
writeChar(x - 1, y, "■■■", Tank.m_color);
writeChar(x - 1, y + 1, " ■ ", Tank.m_color);
break;
case LEFT:
writeChar(x - 1, y - 1, " ■■", Tank.m_color);
writeChar(x - 1, y, "■■ ", Tank.m_color);
writeChar(x - 1, y + 1, " ■■", Tank.m_color);
break;
case RIGHT:
writeChar(x - 1, y - 1, "■■ ", Tank.m_color);
writeChar(x - 1, y, " ■■", Tank.m_color);
writeChar(x - 1, y + 1, "■■ ", Tank.m_color);
break;
}
for (int i = 0;i < 3;i++)
{
for (int i = 0;i < 3;i++)
{
if (Tank.m_Alignment == 100)
{
map.SetDMapValue(Tank.m_PosX + i - 1, Tank.m_PosY + i - 1, 100);
}
else
{
map.SetDMapValue(Tank.m_PosX + i - 1, Tank.m_PosY + i - 1, 200 + Tank.m_Num);
}
}
}
}
//我方坦克初始化
void CTank::CTankINFO(int type)
{
m_Live = 1;
m_Alignment = 100;
m_Dir = UP;
m_Type = type;
m_Blood = 3;
m_Scores = 0;
m_TSpeed = 500;
if (type == 0)
{
m_PosX = 10;
m_PosY = 30;
m_color = 7;
}
else
{
m_PosX = 30;
m_PosY = 30;
m_color = 7;
}
}
//敌方坦克初始化
void CTank::AICTankINFO(int type, int num)
{
m_Live = 1;
m_Alignment = 200;
m_Dir = DOWN;
m_Type = type;
m_Scores = 0;
m_Num = num;
if (type == 2)
{
m_Blood = 1;
m_PosX = 3;
m_PosY = 3;
m_TSpeed = 500;
m_color = 3;
}
else
{
m_Blood = 2;
m_PosX = 30;
m_PosY = 3;
m_TSpeed = 200;
m_color = 0x04;
}
}
//擦除坦克
void CTank::ClsTank(CTank Tank, CMap& map)
{
int x = Tank.m_PosX;
int y = Tank.m_PosY;
writeChar(x - 1, y - 1, " ");
writeChar(x - 1, y, " ");
writeChar(x - 1, y + 1, " ");
for (int i = 0;i < 3;i++)
{
for (int j = 0;j < 3;j++)
{
map.SetDMapValue(Tank.m_PosX + i - 1, Tank.m_PosY + i - 1, 空地);
}
}
}
//坦克的碰撞检测
int CTank::TankCollision(CTank Tank, int dir, CMap& map)
{
int x = Tank.m_PosX;
int y = Tank.m_PosY;
switch (dir)
{
case UP:
if ((map.GetMapValue(x - 1, y - 2) == 丛林 || map.GetMapValue(x, y - 2) == 丛林 || map.GetMapValue(x + 1, y - 2) == 丛林)
|| (map.GetMapValue(x - 1, y + 2) == 丛林 || map.GetMapValue(x, y + 2) == 丛林 || map.GetMapValue(x + 1, y + 2) == 丛林))
{
return 2;
}
else if ((map.GetMapValue(x, y - 2) == 0 && map.GetMapValue(x - 1, y - 2) == 0 && map.GetMapValue(x + 1, y - 2) == 0) &&
(map.GetDMapValue(x, y - 2) == 0 && map.GetDMapValue(x - 1, y - 2) == 0 && map.GetDMapValue(x + 1, y - 2) == 0))
{
return 1;
}
else
{
return 0;
}
case DOWN:
if ((map.GetMapValue(x - 1, y + 2) == 丛林 || map.GetMapValue(x, y + 2) == 丛林 || map.GetMapValue(x + 1, y + 2) == 丛林)
|| (map.GetMapValue(x - 1, y - 2) == 丛林 || map.GetMapValue(x, y - 2) == 丛林 || map.GetMapValue(x - 1, y - 2) == 丛林))
{
return 2;
}
else if ((map.GetMapValue(x, y + 2) == 0 && map.GetMapValue(x - 1, y + 2) == 0 && map.GetMapValue(x + 1, y + 2) == 0) &&
(map.GetDMapValue(x, y + 2) == 0 && map.GetDMapValue(x - 1, y + 2) == 0 && map.GetDMapValue(x + 1, y + 2) == 0))
{
return 1;
}
else
{
return 0;
}
case LEFT:
if ((map.GetMapValue(x - 2, y) == 丛林 || map.GetMapValue(x - 2, y - 1) == 丛林 || map.GetMapValue(x - 2, y + 1) == 丛林)
|| (map.GetMapValue(x + 2, y) == 丛林 || map.GetMapValue(x + 2, y - 1) == 丛林 || map.GetMapValue(x + 2, y + 1) == 丛林))
{
return 2;
}
else if ((map.GetMapValue(x - 2, y) == 0 && map.GetMapValue(x - 2, y - 1) == 0 && map.GetMapValue(x - 2, y + 1) == 0) &&
(map.GetDMapValue(x - 2, y) == 0 && map.GetDMapValue(x - 2, y - 1) == 0 && map.GetDMapValue(x - 2, y + 1) == 0))
{
return 1;
}
else
return 0;
case RIGHT:
if ((map.GetMapValue(x + 2, y) == 丛林 || map.GetMapValue(x + 2, y - 1) == 丛林 || map.GetMapValue(x + 2, y + 1) == 丛林)
|| (map.GetMapValue(x - 2, y) == 丛林 || map.GetMapValue(x - 2, y - 1) == 丛林 || map.GetMapValue(x - 2, y + 1) == 丛林))
{
return 2;
}
else if ((map.GetMapValue(x + 2, y) == 0 && map.GetMapValue(x + 2, y - 1) == 0 && map.GetMapValue(x + 2, y + 1) == 0) &&
(map.GetDMapValue(x + 2, y) == 0 && map.GetDMapValue(x + 2, y - 1) == 0 && map.GetDMapValue(x + 2, y + 1) == 0))
{
return 1;
}
else
return 0;
default:
return 1;
}
}
//坦克移动
void CTank::MoveTank(CTank& Tank, CMap& map,vector<CTank*> CTanklist)
{
int oper = 0;
if (Tank.m_Type == 0)
{
oper = waitkey();
}
else
{
int oper1 = waitkey();
switch (oper1)
{
case 'i':
oper = 119;
break;
case 'k':
oper = 115;
break;
case 'j':
oper = 97;
break;
case 'l':
oper = 100;
break;
case 'h':
oper = 102;
break;
}
}
if (oper != 0)
{
ClsTank(Tank, map);
}
if (TankCollision(Tank,oper ,map))
{
switch (oper)
{
case 'w':
{
if (Tank.m_Dir != UP)
{
Tank.m_Dir = UP;
}
else
{
Tank.m_PosY--;
}
}break;
case 's':
{
if (Tank.m_Dir != DOWN)
{
Tank.m_Dir = DOWN;
}
else
{
Tank.m_PosY++;
}
}break;
case 'a':
{
if (Tank.m_Dir != LEFT)
{
Tank.m_Dir = LEFT;
}
else
{
Tank.m_PosX--;
}
}break;
case 'd':
{
if (Tank.m_Dir != RIGHT)
{
Tank.m_Dir = RIGHT;
}
else
{
Tank.m_PosX++;
}
}break;
case 'f':
{
if (Bullet.Getm_bIsDie() == 0)
{
Bullet.CreateBullet(Tank);
}
}break;
case 'p':
{
SaveCTank(CTanklist,map);
}break;
}
}
if (oper != 0)
{
int a = TankCollision(Tank, oper, map);
DrawTank(Tank, map);
if (a == 2)
{
map.DRAWgrass();
}
}
}
//AI坦克移动
void CTank::MoveAITank(CTank& Tank, CMap& map)
{
if (Tank.m_Live != 0)
{
if (clock() - Tank.m_TPast > Tank.m_TSpeed)
{
Tank.m_TPast = clock();
int oper = rand()%5+1;
//int oper = 5;
if (oper != 0)
{
ClsTank(Tank, map);
}
switch (oper)
{
case 1:
oper = 119;
break;
case 2:
oper = 115;
break;
case 3:
oper = 97;
break;
case 4:
oper = 100;
break;
case 5:
oper = 102;
break;
default:
break;
}
if (TankCollision(Tank, oper, map))
{
switch (oper)
{
case 'w':
{
if (Tank.m_Dir != UP)
{
Tank.m_Dir = UP;
}
else
{
Tank.m_PosY--;
}
}break;
case 's':
{
if (Tank.m_Dir != DOWN)
{
Tank.m_Dir = DOWN;
}
else
{
Tank.m_PosY++;
}
}break;
case 'a':
{
if (Tank.m_Dir != LEFT)
{
Tank.m_Dir = LEFT;
}
else
{
Tank.m_PosX--;
}
}break;
case 'd':
{
if (Tank.m_Dir != RIGHT)
{
Tank.m_Dir = RIGHT;
}
else
{
Tank.m_PosX++;
}
}break;
case 'f':
{
if (Bullet.Getm_bIsDie() == 0)
{
Bullet.CreateBullet(Tank);
}
}
}
}
if (oper != 0)
{
DrawTank(Tank, map);
}
}
}
}
//保存坦克地图
void CTank::SaveCTank( vector<CTank*> CTanklist,CMap& map)
{
FILE* fp = nullptr;
fopen_s(&fp, "CTank.txt", "wb+");
fwrite(&map, sizeof(CMap), 1, fp);
int nSize = CTanklist.size();
fwrite(&nSize, sizeof(int), 1, fp);
for (int i = 0;i < CTanklist.size();i++)
{
fwrite(&(CTanklist[i]->m_Alignment), sizeof(int), 1, fp);
fwrite(&(CTanklist[i]->m_Blood), sizeof(int), 1, fp);
fwrite(&(CTanklist[i]->m_Dir), sizeof(Dir), 1, fp);
fwrite(&(CTanklist[i]->m_Live), sizeof(int), 1, fp);
fwrite(&(CTanklist[i]->m_Num), sizeof(int), 1, fp);
fwrite(&(CTanklist[i]->m_PosX), sizeof(int), 1, fp);
fwrite(&(CTanklist[i]->m_PosY), sizeof(int), 1, fp);
fwrite(&(CTanklist[i]->m_Scores), sizeof(Dir), 1, fp);
fwrite(&(CTanklist[i]->m_TPast), sizeof(int), 1, fp);
fwrite(&(CTanklist[i]->m_TSpeed), sizeof(int), 1, fp);
fwrite(&(CTanklist[i]->m_Type), sizeof(int), 1, fp);
fwrite(&(CTanklist[i]->m_color), sizeof(int), 1, fp);
}
fclose(fp);
fp = nullptr;
}
子弹类
#pragma once
#include<time.h>
class CTank;
class CMap;
#include<vector>
using std::vector;
class CBullet
{
public:
//接口
int Getm_bIsDie();
int GetbALignment();
//运算符重载
bool operator=(CTank &Tank);
bool operator==(CTank& Tank);
//生成子弹
CBullet CreateBullet(CTank &Tank);
//擦子弹
void ClsBullet(CBullet& Bullet, CMap& map);
//画子弹
void DrawBullet(CBullet& Bullet, CMap& map);
//移动子弹
void MoveBullet(CBullet& Bullet,CMap &map, vector<CTank*> CTanklist);
//子弹碰撞检测
bool BulletColloson(CBullet& Bullet,CMap& map, vector<CTank*> CTanklist);
private:
bool m_bIsDie=0;//子弹是否存在
int m_bALignment;//子弹所在的阵营
int m_bPosX;
int m_bPosY;//子弹坐标
int m_bDir;//子弹方向
int m_bType;//子弹类型
int m_bATK;//子弹攻击力
int m_bSpeed;//子弹的速度
int m_bPast; //子弹的时钟
int m_color;
};
//上面是.h的文件 下面是.cpp的文件
#include "CBullet.h"
#include"CTank.h"
#include"工具.h"
//接口
int CBullet::Getm_bIsDie()
{
return m_bIsDie;
}
int CBullet::GetbALignment()
{
return m_bALignment;
}
//运算符重载
bool CBullet::operator=(CTank &Tank)
{
m_bDir = Tank.GetDIR();
m_bPosX = Tank.GetPosX();
m_bPosY = Tank.GetPosY();
m_bALignment = Tank.GetAlignment();
m_bIsDie = 0;
m_color = Tank.m_color;
switch (Tank.GetDIR())
{
case UP:
m_bPosY -= 2;
break;
case DOWN:
m_bPosY += 2;
break;
case LEFT:
m_bPosX -= 2;
break;
case RIGHT:
m_bPosX += 2;
break;
}
return true;
}
bool CBullet::operator==(CTank& Tank)
{
int nTankPosX = Tank.GetPosX();
int nTankPosY = Tank.GetPosY();
if (Tank.GetDIR())
{
for (int nposY = nTankPosY - 1;nposY < nTankPosY + 2;nposY++)
{
for (int nposX = nTankPosX - 1;nposX < nTankPosX + 2;nposX++)
{
if ((m_bPosX == nposX) && (m_bPosY == nposY))
{
return true;
}
}
}
}
return false;
}
//生成子弹
CBullet CBullet::CreateBullet(CTank& Tank)
{
*this = Tank;
this->m_bIsDie = 1;
this->m_bSpeed = 50;
this->m_bPast = clock();
if (Tank.m_Type > 2)
{
this->m_bATK = 3;
}
else
{
this->m_bATK = 1;
}
return *this;
}
//擦子弹
void CBullet::ClsBullet(CBullet& Bullet, CMap& map)
{
writeChar(Bullet.m_bPosX, Bullet.m_bPosY, " ");
map.SetDMapValue(Bullet.m_bPosX, Bullet.m_bPosY, 0);
}
//画子弹
void CBullet::DrawBullet(CBullet& Bullet, CMap& map)
{
writeChar(Bullet.m_bPosX, Bullet.m_bPosY, "oo",Bullet.m_color);
map.SetDMapValue(Bullet.m_bPosX, Bullet.m_bPosY, 10);
}
//移动子弹
void CBullet::MoveBullet(CBullet& Bullet,CMap& map, vector<CTank*> CTanklist)
{
if (Bullet.m_bIsDie == 1)
{
if (clock() - Bullet.m_bPast > Bullet.m_bSpeed)
{
Bullet.m_bPast = clock();
if (map.GetMapValue(Bullet.m_bPosX, Bullet.m_bPosY) == 河流 || map.GetMapValue(Bullet.m_bPosX, Bullet.m_bPosY) == 丛林)
{
}
else
{
ClsBullet(Bullet, map);
}
if (BulletColloson(Bullet, map, CTanklist))
{
switch (Bullet.m_bDir)
{
case UP:
Bullet.m_bPosY--;
break;
case DOWN:
Bullet.m_bPosY++;
break;
case LEFT:
Bullet.m_bPosX--;
break;
case RIGHT:
Bullet.m_bPosX++;
break;
}
if (map.GetMapValue(Bullet.m_bPosX, Bullet.m_bPosY) == 河流 || map.GetMapValue(Bullet.m_bPosX, Bullet.m_bPosY) == 丛林)
{
return;
}
DrawBullet(Bullet, map);
}
}
}
}
//子弹碰撞
bool CBullet::BulletColloson(CBullet& Bullet,CMap &map, vector<CTank*> CTanklist)
{
int nPox = Bullet.m_bPosX;
int nPoY = Bullet.m_bPosY;
if (map.GetMapValue(nPox, nPoY) == 边界)
{
writeChar(nPox, nPoY, "■",15);
Bullet.m_bIsDie = 0;
return false;
}
if (map.GetMapValue(nPox, nPoY) == 木墙)
{
writeChar(nPox, nPoY, " ");
map.SetMapValue(nPox, nPoY, 0);
Bullet.m_bIsDie = 0;
return false;
}
if (map.GetMapValue(nPox, nPoY) == 河流)
{
return true;
}
if (map.GetMapValue(nPox, nPoY) == 丛林)
{
return true;
}
switch (Bullet.m_bDir)
{
case UP:
nPoY--;
break;
case DOWN:
nPoY++;
break;
case LEFT:
nPox--;
break;
case RIGHT:
nPox++;
break;
}
//子弹和坦克的碰撞检测
for (int i = 0;i < CTanklist.size();i++)
{
if (Bullet == *CTanklist[i])
{
if (Bullet.m_bALignment != CTanklist[i]->GetAlignment())
{
Bullet.m_bIsDie = 0;
CTanklist[i]->m_Blood-=Bullet.m_bATK;
if (CTanklist[i]->m_Blood == 0)
{
CTanklist[i]->ClsTank(*CTanklist[i], map);
CTanklist[i]->m_Live = 0;
CTanklist[0]->m_Scores += 50;
}
return false;
}
}
}
//子弹和子弹的碰撞
if (map.GetDMapValue(nPox, nPoY) == 10)
{
writeChar(Bullet.m_bPosX, Bullet.m_bPosY, " ");
map.SetMapValue(Bullet.m_bPosX, Bullet.m_bPosY, 木墙);
Bullet.m_bIsDie = 0;
return false;
}
if (map.GetMapValue(nPox, nPoY) == 老鹰)
{
writeChar(Bullet.m_bPosX, Bullet.m_bPosY, " ");
Bullet.m_bIsDie = 0;
writeChar(15, 15, "GOOD GAME!!!", 4);
getchar();
exit(1);
}
return true;
}
游戏类
#pragma once
#include"CBullet.h"
#include"CMap.h"
#include"CTank.h"
#include<vector>
using std::vector;
class CGame
{
public:
void startGame();//单人开始游戏
void startGame0();//第三关
void startGame2();//双人开始游戏
void startGame3();//编辑地图开始游戏
void startGame4();//读档开始开始游戏
vector<CTank*> CTanklist; //坦克列表
public://自制地图
void KeyEventProc(KEY_EVENT_RECORD ker);
int MessageLoop(CMap &map);
void MouseEventProc(MOUSE_EVENT_RECORD mer, CMap& map);
public:
//读取文件
void readCTank(CMap& map);
};
//上面是.h的文件 下面是.cpp的文件
#include "CGame.h"
#include"工具.h"
#include<Windows.h>
#include <conio.h>
//键盘事件处理函数
void CGame::KeyEventProc(KEY_EVENT_RECORD ker)
{
}
//消息处理函数
int CGame::MessageLoop(CMap& map)
{
writeChar(40, 7, "按任意键退出设置地图",2);
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD stcRecord = { 0 };
DWORD dwRead;
SetConsoleMode(hStdin, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
while (1)
{
//等待事件
ReadConsoleInput(hStdin, &stcRecord, 1, &dwRead);
//处理事件
if (stcRecord.EventType == KEY_EVENT)
{//键盘事件
KeyEventProc(stcRecord.Event.KeyEvent);
return 0;
}
else if (stcRecord.EventType == MOUSE_EVENT)
{//鼠标事件
MouseEventProc(stcRecord.Event.MouseEvent, map);
}
}
}
//鼠标事件处理函数
void CGame::MouseEventProc(MOUSE_EVENT_RECORD mer, CMap& map)
{
switch (mer.dwEventFlags)
{
case 0:
{
if (mer.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
{
writeChar(mer.dwMousePosition.X / 2, mer.dwMousePosition.Y, "■");
map.SetMapValue(mer.dwMousePosition.X/2, mer.dwMousePosition.Y, 边界);
}
else if (mer.dwButtonState == RIGHTMOST_BUTTON_PRESSED)
{
writeChar(mer.dwMousePosition.X / 2, mer.dwMousePosition.Y, "□");
map.SetMapValue(mer.dwMousePosition.X/2, mer.dwMousePosition.Y, 木墙);
}
break;
}
}
}
//读取文件
void CGame::readCTank(CMap &map)
{
FILE* fp = nullptr;
fopen_s(&fp, "CTank.txt", "rb+");
fread(&map, sizeof(CMap), 1, fp);
int nSize = 0;
fread(&nSize, sizeof(int), 1, fp);
//CTanklist.resize(nSize);
for (int i = 0;i < nSize;i++)
{
CTank* tank = new CTank();
int a = 0;
fread(&a, sizeof(int), 1, fp);
tank->m_Alignment = a;
fread(&a, sizeof(int), 1, fp);
tank->m_Blood = a;
fread(&a, sizeof(Dir), 1, fp);
tank->m_Dir =(Dir) a;
fread(&a, sizeof(int), 1, fp);
tank->m_Live = a;
fread(&a, sizeof(int), 1, fp);
tank->m_Num = a;
fread(&a, sizeof(int), 1, fp);
tank->m_PosX = a;
fread(&a, sizeof(int), 1, fp);
tank->m_PosY = a;
fread(&a, sizeof(Dir), 1, fp);
tank->m_Scores = a;
fread(&a, sizeof(int), 1, fp);
tank->m_TPast = a;
fread(&a, sizeof(int), 1, fp);
tank->m_TSpeed = a;
fread(&a, sizeof(int), 1, fp);
tank->m_Type = a;
fread(&a, sizeof(int), 1, fp);
tank->m_color = a;
CTanklist.push_back(tank);
}
fclose(fp);
fp = nullptr;
}
//单人开始游戏
void CGame::startGame()
{
srand(time(NULL));
CMap map1;
map1.DrawMap();
map1.DrawRiver();
map1.DrawWall();
map1.DRAWgrass();
map1.DrawFortress();
//MessageLoop(map1);
CTank* Tank0 = new CTank();
//CTank* Tank1 = new CTank();
CTank* Tank2 = new CTank();
CTank* Tank3 = new CTank();
//初始化坦克
Tank0->CTankINFO(0);
//Tank1->CTankINFO(1);//玩家B
Tank2->AICTankINFO(2,2);
Tank3->AICTankINFO(3,3);
CTanklist.push_back(Tank0);
//CTanklist.push_back(Tank1);
CTanklist.push_back(Tank2);
CTanklist.push_back(Tank3);
for (int i = 0;i < CTanklist.size();i++)
{
CTanklist[i]->DrawTank(*CTanklist[i], map1);
}
writeChar(48, 2, "第一关", 12);
writeChar(48, 4, "分数:", 13);
writeChar(40, 6, "游戏说明:", 11);
writeChar(45, 6, "游戏目标:保护堡垒击杀敌方坦克", 9);
writeChar(40, 8, "按键说明:", 14);
writeChar(45, 8, "玩家A", 1);
writeChar(45, 10, "w/上,s/下,a/左,d/右,f/发炮弹", 1);
writeChar(45, 12, "P键保存", 2);
while (true)
{
Tank0->MoveTank(*Tank0, map1,CTanklist);
//Tank1->MoveTank(*Tank1, map1, CTanklist);
Tank2->MoveAITank(*Tank2, map1 );
Tank3->MoveAITank(*Tank3, map1 );
CTanklist.clear();
if (Tank0->Getlive() != 0)
{
CTanklist.push_back(Tank0);
}
/*if (Tank1->Getlive() != 0)
{
CTanklist.push_back(Tank1);
}*/
if (Tank2->Getlive() != 0)
{
CTanklist.push_back(Tank2);
}
if (Tank3->Getlive() != 0)
{
CTanklist.push_back(Tank3);
}
Tank0->Bullet.MoveBullet(Tank0->Bullet, map1, CTanklist);
//Tank1->Bullet.MoveBullet(Tank1->Bullet, map1, CTanklist);
Tank2->Bullet.MoveBullet(Tank2->Bullet, map1, CTanklist);
Tank3->Bullet.MoveBullet(Tank3->Bullet, map1, CTanklist);
writeChar2(51, 4, Tank0->m_Scores, 10);
if (Tank0->Getbool() == 0)
{
writeChar(15, 15, "GOOD GAME!!!", 4);
getchar();
exit(1);
}
if (Tank2->m_Live == 0 && Tank3->m_Live == 0)
{
Tank0->ClsTank(*Tank0, map1);
system("cls");
CTanklist.clear();
writeChar(0, 0, "恭喜通关", 4);
writeChar(0, 1, "进入下一关", 4);
writeChar(0, 2, "加载中....", 4);
Sleep(1500);
system("cls");
return;
}
}
}
//双人开始游戏
void CGame::startGame2()
{
srand(time(NULL));
CMap map1;
map1.DrawMap();
map1.DrawRiver();
map1.DrawWall();
map1.DRAWgrass();
map1.DrawFortress();
//MessageLoop(map1);
CTank* Tank0 = new CTank();
CTank* Tank1 = new CTank();
CTank* Tank2 = new CTank();
CTank* Tank3 = new CTank();
//初始化坦克
Tank0->CTankINFO(0);
Tank1->CTankINFO(1);//玩家B
Tank2->AICTankINFO(2, 2);
Tank3->AICTankINFO(3, 3);
CTanklist.push_back(Tank0);
CTanklist.push_back(Tank1);
CTanklist.push_back(Tank2);
CTanklist.push_back(Tank3);
for (int i = 0;i < CTanklist.size();i++)
{
CTanklist[i]->DrawTank(*CTanklist[i], map1);
}
writeChar(48, 2, "第一关", 12);
writeChar(48, 4, "分数:", 13);
writeChar(40, 6, "游戏说明:", 11);
writeChar(45, 6, "游戏目标:保护堡垒击杀敌方坦克", 9);
writeChar(40, 8, "按键说明:", 14);
writeChar(45, 8, "玩家A", 1);
writeChar(45, 10, "w/上,s/下,a/左,d/右,f/发炮弹", 1);
writeChar(45, 12, "玩家B", 13);
writeChar(45, 14, "i/上,k/下,j/左,l/右,h/发炮弹", 13);
writeChar(45, 16, "P键保存", 2);
while (true)
{
CTanklist.clear();
Tank0->MoveTank(*Tank0, map1, CTanklist);
Tank1->MoveTank(*Tank1, map1, CTanklist);
Tank2->MoveAITank(*Tank2, map1);
Tank3->MoveAITank(*Tank3, map1);
if (Tank0->Getlive() != 0)
{
CTanklist.push_back(Tank0);
}
if (Tank1->Getlive() != 0)
{
CTanklist.push_back(Tank1);
}
if (Tank2->Getlive() != 0)
{
CTanklist.push_back(Tank2);
}
if (Tank3->Getlive() != 0)
{
CTanklist.push_back(Tank3);
}
Tank0->Bullet.MoveBullet(Tank0->Bullet, map1, CTanklist);
Tank1->Bullet.MoveBullet(Tank1->Bullet, map1, CTanklist);
Tank2->Bullet.MoveBullet(Tank2->Bullet, map1, CTanklist);
Tank3->Bullet.MoveBullet(Tank3->Bullet, map1, CTanklist);
if (Tank0->Getbool() == 0)
{
writeChar(15, 15, "GOOD GAME!!!", 4);
getchar();
exit(1);
}
if (Tank2->m_Live == 0 && Tank3->m_Live == 0)
{
writeChar(15, 15, "GOOD GAME!!!", 4);
getchar();
exit(1);
}
}
}
//自制地图开始游戏
void CGame::startGame3()
{
srand(time(NULL));
CMap map1;
map1.DrawMap();
MessageLoop(map1);
CTank* Tank0 = new CTank();
//CTank* Tank1 = new CTank();
CTank* Tank2 = new CTank();
CTank* Tank3 = new CTank();
//初始化坦克
Tank0->CTankINFO(0);
//Tank1->CTankINFO(1);//玩家B
Tank2->AICTankINFO(2, 2);
Tank3->AICTankINFO(3, 3);
CTanklist.push_back(Tank0);
//CTanklist.push_back(Tank1);
CTanklist.push_back(Tank2);
CTanklist.push_back(Tank3);
for (int i = 0;i < CTanklist.size();i++)
{
CTanklist[i]->DrawTank(*CTanklist[i], map1);
}
writeChar(48, 2, "第一关", 12);
writeChar(48, 4, "分数:", 13);
writeChar(40, 6, "游戏说明:", 11);
writeChar(45, 6, "游戏目标:保护堡垒击杀敌方坦克", 9);
writeChar(40, 8, "按键说明:", 14);
writeChar(45, 8, "玩家A", 1);
writeChar(45, 10, "w/上,s/下,a/左,d/右,f/发炮弹", 1);
writeChar(45, 12, "P键保存", 2);
while (true)
{
CTanklist.clear();
Tank0->MoveTank(*Tank0, map1, CTanklist);
//Tank1->MoveTank(*Tank1, map1, CTanklist);
Tank2->MoveAITank(*Tank2, map1);
Tank3->MoveAITank(*Tank3, map1);
if (Tank0->Getlive() != 0)
{
CTanklist.push_back(Tank0);
}
/*if (Tank1->Getlive() != 0)
{
CTanklist.push_back(Tank1);
}*/
if (Tank2->Getlive() != 0)
{
CTanklist.push_back(Tank2);
}
if (Tank3->Getlive() != 0)
{
CTanklist.push_back(Tank3);
}
Tank0->Bullet.MoveBullet(Tank0->Bullet, map1, CTanklist);
//Tank1->Bullet.MoveBullet(Tank1->Bullet, map1, CTanklist);
Tank2->Bullet.MoveBullet(Tank2->Bullet, map1, CTanklist);
Tank3->Bullet.MoveBullet(Tank3->Bullet, map1, CTanklist);
if (Tank0->Getbool() == 0)
{
writeChar(15, 15, "GOOD GAME!!!", 4);
getchar();
exit(1);
}
if (Tank2->m_Live == 0 && Tank3->m_Live == 0)
{
writeChar(15, 15, "GOOD GAME!!!", 4);
getchar();
exit(1);
}
}
}
//读档开始游戏
void CGame::startGame4()
{
srand(time(NULL));
CMap map1;
readCTank(map1);
map1.DrawMap();
map1.DrawRiver();
map1.DrawWall();
map1.DRAWgrass();
map1.DrawFortress();
//MessageLoop(map1);
CTank* Tank0 = CTanklist[0];
//CTank* Tank1 = new CTank();
CTank* Tank2 = CTanklist[1];
CTank* Tank3 = CTanklist[2];
//初始化坦克
//Tank0->CTankINFO(0);
//Tank1->CTankINFO(1);//玩家B
//Tank2->AICTankINFO(2, 2);
//Tank3->AICTankINFO(3, 3);
//CTanklist.push_back(Tank0);
//CTanklist.push_back(Tank1);
//CTanklist.push_back(Tank2);
//CTanklist.push_back(Tank3);
for (int i = 0;i < CTanklist.size();i++)
{
CTanklist[i]->DrawTank(*CTanklist[i], map1);
}
writeChar(48, 2, "第一关", 12);
writeChar(48, 4, "分数:", 13);
writeChar(40, 6, "游戏说明:", 11);
writeChar(45, 6, "游戏目标:保护堡垒击杀敌方坦克", 9);
writeChar(40, 8, "按键说明:", 14);
writeChar(45, 8, "玩家A", 1);
writeChar(45, 10, "w/上,s/下,a/左,d/右,f/发炮弹", 1);
writeChar(45, 12, "玩家B", 13);
writeChar(45, 14, "i/上,k/下,j/左,l/右,h/发炮弹", 13);
writeChar(45, 16, "P键保存", 2);
while (true)
{
Tank0->MoveTank(*Tank0, map1,CTanklist);
//Tank1->MoveTank(*Tank1, map1,CTanklist);
Tank2->MoveAITank(*Tank2, map1);
Tank3->MoveAITank(*Tank3, map1);
CTanklist.clear();
if (Tank0->Getlive() != 0)
{
CTanklist.push_back(Tank0);
}
/*if (Tank1->Getlive() != 0)
{
CTanklist.push_back(Tank1);
}*/
if (Tank2->Getlive() != 0)
{
CTanklist.push_back(Tank2);
}
if (Tank3->Getlive() != 0)
{
CTanklist.push_back(Tank3);
}
Tank0->Bullet.MoveBullet(Tank0->Bullet, map1, CTanklist);
//Tank1->Bullet.MoveBullet(Tank1->Bullet, map1, bulletlist, CTanklist);
Tank2->Bullet.MoveBullet(Tank2->Bullet, map1, CTanklist);
Tank3->Bullet.MoveBullet(Tank3->Bullet, map1, CTanklist);
if (Tank0->Getbool() == 0)
{
writeChar(15,15,"GOOD GAME!!!",4);
getchar();
exit(1);
}
if (Tank2->m_Live == 0 && Tank3->m_Live == 0)
{
writeChar(25, 25, "GOOD GAME!!!", 4);
getchar();
exit(1);
}
}
}
//第二关
void CGame::startGame0()
{
srand(time(NULL));
CMap map1;
map1.DrawMap();
map1.DrawRiver();
//map1.DrawWall();
map1.DRAWgrass();
map1.DrawFortress();
//MessageLoop(map1);
CTank* Tank0 = new CTank();
//CTank* Tank1 = new CTank();
CTank* Tank2 = new CTank();
CTank* Tank3 = new CTank();
//初始化坦克
Tank0->CTankINFO(0);
//Tank1->CTankINFO(1);//玩家B
Tank2->AICTankINFO(2, 2);
Tank3->AICTankINFO(3, 3);
CTanklist.push_back(Tank0);
//CTanklist.push_back(Tank1);
CTanklist.push_back(Tank2);
CTanklist.push_back(Tank3);
for (int i = 0;i < CTanklist.size();i++)
{
CTanklist[i]->DrawTank(*CTanklist[i], map1);
}
writeChar(48, 2, "第二关", 12);
writeChar(48, 4, "分数:", 13);
writeChar(40, 6, "游戏说明:", 11);
writeChar(45, 6, "游戏目标:保护堡垒击杀敌方坦克", 9);
writeChar(40, 8, "按键说明:", 14);
writeChar(45, 8, "玩家A", 1);
writeChar(45, 10, "w/上,s/下,a/左,d/右,f/发炮弹", 1);
writeChar(45, 12, "P键保存", 2);
while (true)
{
Tank0->MoveTank(*Tank0, map1, CTanklist);
//Tank1->MoveTank(*Tank1, map1, CTanklist);
Tank2->MoveAITank(*Tank2, map1);
Tank3->MoveAITank(*Tank3, map1);
CTanklist.clear();
if (Tank0->Getlive() != 0)
{
CTanklist.push_back(Tank0);
}
/*if (Tank1->Getlive() != 0)
{
CTanklist.push_back(Tank1);
}*/
if (Tank2->Getlive() != 0)
{
CTanklist.push_back(Tank2);
}
if (Tank3->Getlive() != 0)
{
CTanklist.push_back(Tank3);
}
Tank0->Bullet.MoveBullet(Tank0->Bullet, map1, CTanklist);
//Tank1->Bullet.MoveBullet(Tank1->Bullet, map1, CTanklist);
Tank2->Bullet.MoveBullet(Tank2->Bullet, map1, CTanklist);
Tank3->Bullet.MoveBullet(Tank3->Bullet, map1, CTanklist);
writeChar2(51, 4, Tank0->m_Scores, 10);
if (Tank0->Getbool() == 0)
{
writeChar(15, 15, "GOOD GAME!!!", 4);
getchar();
exit(1);
}
if (Tank2->m_Live == 0 && Tank3->m_Live == 0)
{
writeChar(15, 15, "恭喜通关", 4);
getchar();
exit(1);
}
}
}
工具函数
#pragma once
#define Mapx 40
#define Mapy 40
#define 空地 0
#define 边界 1
#define 河流 2
#define 丛林 3
#define 木墙 4
#define 老鹰 5
//打印文字和图形
void writeChar(int x, int y, const char* szBuf, int color=0);
//打印变量的值
void writeChar2(int x, int y, int a, int color = 0);
//获取按键
int waitkey();
//隐藏光标
void ShouCursor(bool isShow);
//上面是.h的文件 下面是.cpp的文件
#include"工具.h"
#include<Windows.h>
#include <conio.h>
#include<iostream>
#include<time.h>
//打印文字和图形
void writeChar(int x, int y, const char* szBuf, int color)
{
COORD pos = { x * 2,y };
HANDLE hStout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hStout, pos);
SetConsoleTextAttribute(hStout, color);
printf(szBuf);
}
//打印变量的值
void writeChar2(int x, int y, int a , int color)
{
COORD pos = { x * 2,y };
HANDLE hStout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hStout, pos);
SetConsoleTextAttribute(hStout, color);
printf("%d",a);
}
//获取按键
int waitkey()
{
if (_kbhit())
{
return _getch();
}
return 0;
}
//隐藏光标
void ShouCursor(bool isShow) {
HANDLE hOutStd = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 1;
cci.bVisible = isShow;
SetConsoleCursorInfo(hOutStd, &cci);
}
主函数
#include<iostream>
#include<Windows.h>
#include <conio.h>
#include"CTank.h"
#include"CBullet.h"
#include"工具.h"
#include "CMap.h"
#include"CGame.h"
#pragma comment(lib,"winmm.lib")
int main()
{
system("mode con cols=120 lines=50");
PlaySoundA("D:/C语言项目/坦克大战C/坦克大战/坦克大战/菊次郎的夏天.wav", NULL, SND_ASYNC | SND_NODEFAULT);
ShouCursor(0);
while (true)
{
CGame game1;
writeChar(10, 10, "坦克大战",7);
writeChar(10, 11, "1.开始游戏",7);
writeChar(10, 12, "2.双人游戏",7);
writeChar(10, 13, "3.自制地图",7);
writeChar(10, 14, "4.继续游戏",7);
writeChar(10, 15, "5.退出游戏",7);
writeChar(10, 16, "",7);
int oper = getchar();
switch (oper)
{
case '1':
{
system("cls");
game1.startGame();
game1.startGame0();
}
case '2':
{
system("cls");
game1.startGame2();
}
case '3':
{
system("cls");
game1.startGame3();
}
case '4':
{
system("cls");
game1.startGame4();
}
case '5':
{
system("cls");
writeChar(10, 10, "再来玩哟");
exit(1);
}
default:
break;
}
}
}
项目总结
1 代码过于繁琐 可以精简 。
2.可以使用继承和多态进行优化。
3.注释太少(估计过段时间也就上帝能看得懂我的代码了)。
4.敌方坦克太傻了 可以加入Astart算法让他自行寻路。
5.取名字虽然是个难事 尽量见名知意 或者就多注释。