C++ 坦克大战小游戏EGE图形界面

C++ EGE 实现坦克大战小游戏

因为有过一次用EGE写小游戏的经验,所以这一次写坦克大战快了很多。并且使用对象编程也简化了很多编程时繁琐的步骤。
写出坦克大战使我在学习编程的道路上又迈出了一大步。

如果您需要图片素材的,我可以单独发给您。

技术环节:
编译环境:Windows VS2019

需求:
控制坦克移动发射炮弹,炮弹可以消灭敌军坦克,且可以消灭砖块。坦克遇到方块会被挡住。敌军消灭我军三次或基地被毁则游戏失败,共摧毁十次敌方坦克游戏胜利。

思路:
先写出坦克的父类,我方坦克类和敌方坦克类继承坦克父类,实例化我方坦克和敌方坦克。地图使用list容器存储。

在代码注释中标注了每一步是怎么实现的。

注意:
因为我在程序中用了一些不规范的写法,所以要在VS中正常编译运行,需要右键源文件->属性->C/C+±>符合模式,改为否。

包含<graphics.h>图形库需要提前配置EGE图形库。
如要在其他graphics图形库下编译,可能需要修改某些地方。

运行效果:
1
2
3

#include <graphics.h>	//图形库
#include <ctime>		//time();
#include <list>			//list容器

using namespace std;	//标准命名空间 list等

//设置图片对象中图片的宽高  全局函数
//参数:宽、高、对象名
void setimage(int pwidth, int pheight, PIMAGE img_1);

//地图全局结构
struct mapstr
{
	int m_x;	//xy坐标
	int m_y;
	int prop;	//属性
};

//地图类
class Mymap
{
private:
	list<mapstr> listmap;		//地图容器,存储全地图信息,全地图1350个20*20的格子

public:
	//设置地图
	Mymap()
	{
		mapstr temp;

		//构造函数为链表容器中的地图赋值

		//全地图横向45个格子 竖向30个格子

		//基地部分
		{
			temp.prop = 0;
			for (int i = 0; i < 4; i++) { temp.m_x = 380 + i * 20; temp.m_y = 540; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 380 + i * 20; temp.m_y = 520; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 380; temp.m_y = 560 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 360; temp.m_y = 520 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 440; temp.m_y = 560 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 460; temp.m_y = 520 + i * 20; listmap.push_back(temp); }
			temp.prop = 4, temp.m_x = 400, temp.m_y = 560;	listmap.push_back(temp);
		}

		//左上角部分
		{
			temp.prop = 0;
			//左上角单独砖块
			for (int i = 0; i < 2; i++) { temp.m_x = 40 + i * 20; temp.m_y = 80; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 40 + i * 20; temp.m_y = 100; listmap.push_back(temp); }
			//竖铁块
			for (int i = 0; i < 4; i++) { temp.m_x = 160; temp.m_y = i * 20; temp.prop = 1; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 180; temp.m_y = i * 20; listmap.push_back(temp); }
			//砖块
			for (int i = 0; i < 4; i++) { temp.m_x = 160; temp.m_y = 160 + i * 20; temp.prop = 0; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 180; temp.m_y = 160 + i * 20; listmap.push_back(temp); }
			//草块
			for (int i = 0; i < 4; i++) { temp.m_x = 0; temp.m_y = 200 + i * 20; temp.prop = 2; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 20; temp.m_y = 200 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 40 + i * 20; temp.m_y = 240; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 40 + i * 20; temp.m_y = 260; listmap.push_back(temp); }
		}

		//中上部分
		{
			//铁块
			for (int i = 0; i < 2; i++) { temp.m_x = 320; temp.m_y = i * 20; temp.prop = 1; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 340; temp.m_y = i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 280 + i * 20; temp.m_y = 160; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 280 + i * 20; temp.m_y = 180; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 400 + i * 20; temp.m_y = 200; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 400 + i * 20; temp.m_y = 220; listmap.push_back(temp); }
			//砖块
			for (int i = 0; i < 4; i++) { temp.m_x = 320; temp.m_y = 40 + i * 20; temp.prop = 0; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 340; temp.m_y = 40 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 240; temp.m_y = 200 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 260; temp.m_y = 200 + i * 20; listmap.push_back(temp); }
		}

		//右上部分
		{
			//砖块
			for (int i = 0; i < 4; i++) { temp.m_x = 480; temp.m_y = 40 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 500; temp.m_y = 40 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 480; temp.m_y = 160 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 500; temp.m_y = 160 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 600; temp.m_y = 40 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 620; temp.m_y = 40 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 600; temp.m_y = 160 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 620; temp.m_y = 160 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 6; i++) { temp.m_x = 680 + i * 20; temp.m_y = 200; listmap.push_back(temp); }
			for (int i = 0; i < 6; i++) { temp.m_x = 680 + i * 20; temp.m_y = 220; listmap.push_back(temp); }
			for (int i = 0; i < 6; i++) { temp.m_x = 760; temp.m_y = 0 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 6; i++) { temp.m_x = 780; temp.m_y = 0 + i * 20; listmap.push_back(temp); }
			//草块
			for (int i = 0; i < 6; i++) { temp.m_x = 560; temp.m_y = 160 + i * 20; temp.prop = 2; listmap.push_back(temp); }
			for (int i = 0; i < 6; i++) { temp.m_x = 580; temp.m_y = 160 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 520; temp.m_y = 160 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 540; temp.m_y = 160 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 860; temp.m_y = 80 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 880; temp.m_y = 80 + i * 20; listmap.push_back(temp); }
			//铁块
			for (int i = 0; i < 4; i++) { temp.m_x = 520 + i * 20; temp.m_y = 80; temp.prop = 1; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 520 + i * 20; temp.m_y = 100; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 640 + i * 20; temp.m_y = 160; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 640 + i * 20; temp.m_y = 180; listmap.push_back(temp); }
			for (int i = 0; i < 6; i++) { temp.m_x = 800 + i * 20; temp.m_y = 200; listmap.push_back(temp); }
			for (int i = 0; i < 6; i++) { temp.m_x = 800 + i * 20; temp.m_y = 220; listmap.push_back(temp); }
		}

		//左下部分
		{
			//铁块
			for (int i = 0; i < 2; i++) { temp.m_x = i * 20; temp.m_y = 360; temp.prop = 1; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = i * 20; temp.m_y = 380; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 160; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 180; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			//砖块
			for (int i = 0; i < 12; i++) { temp.m_x = 40; temp.m_y = 360 + i * 20; temp.prop = 0; listmap.push_back(temp); }
			for (int i = 0; i < 12; i++) { temp.m_x = 60; temp.m_y = 360 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 40 + i * 20; temp.m_y = 280; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 40 + i * 20; temp.m_y = 300; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 160; temp.m_y = 400 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 180; temp.m_y = 400 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 160; temp.m_y = 560 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 180; temp.m_y = 560 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 240 + i * 20; temp.m_y = 240; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 240 + i * 20; temp.m_y = 260; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 280; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 300; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 320; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 340; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 360; temp.m_y = 400 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 380; temp.m_y = 400 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 400; temp.m_y = 400 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 420; temp.m_y = 400 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 440; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 460; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 480; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 500; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 520; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 540; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			//草块
			for (int i = 0; i < 10; i++) { temp.m_x = 200 + i * 20; temp.m_y = 280; temp.prop = 2; listmap.push_back(temp); }
			for (int i = 0; i < 10; i++) { temp.m_x = 200 + i * 20; temp.m_y = 300; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 200 + i * 20; temp.m_y = 320; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 200 + i * 20; temp.m_y = 340; listmap.push_back(temp); }
		}

		//右下部分
		{
			//砖块
			for (int i = 0; i < 8; i++) { temp.m_x = 600; temp.m_y = 320 + i * 20; temp.prop = 0; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 620; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 560; temp.m_y = 520 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 580; temp.m_y = 520 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 600 + i * 20; temp.m_y = 560; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 600 + i * 20; temp.m_y = 580; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 680 + i * 20; temp.m_y = 520; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 680 + i * 20; temp.m_y = 540; listmap.push_back(temp); }
			for (int i = 0; i < 7; i++) { temp.m_x = 760 + i * 20; temp.m_y = 320; listmap.push_back(temp); }
			for (int i = 0; i < 7; i++) { temp.m_x = 760 + i * 20; temp.m_y = 340; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 800; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 8; i++) { temp.m_x = 820; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			//铁块
			for (int i = 0; i < 4; i++) { temp.m_x = 640; temp.m_y = 320 + i * 20; temp.prop = 1; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 660; temp.m_y = 320 + i * 20; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 680; temp.m_y = 320 + i * 20; temp.prop = 1; listmap.push_back(temp); }
			for (int i = 0; i < 2; i++) { temp.m_x = 700; temp.m_y = 320 + i * 20; temp.prop = 1; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 820 + i * 20; temp.m_y = 480; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 820 + i * 20; temp.m_y = 500; listmap.push_back(temp); }
			//草块
			for (int i = 0; i < 4; i++) { temp.m_x = 560; temp.m_y = 360 + i * 20; temp.prop = 2; listmap.push_back(temp); }
			for (int i = 0; i < 4; i++) { temp.m_x = 580; temp.m_y = 360 + i * 20; listmap.push_back(temp); }
		}
	}

	//显示地图
	void printmap(list<mapstr>& listmap)
	{
		PIMAGE mapprop_0 = newimage();
		getimage(mapprop_0, "坦克大战完整素材\\砖块.png");
		setimage(20, 20, mapprop_0);
		PIMAGE mapprop_1 = newimage();
		getimage(mapprop_1, "坦克大战完整素材\\铁块.png");
		setimage(20, 20, mapprop_1);
		PIMAGE mapprop_2 = newimage();
		getimage(mapprop_2, "坦克大战完整素材\\草块.png");
		setimage(20, 20, mapprop_2);
		PIMAGE mapprop_4 = newimage();
		getimage(mapprop_4, "坦克大战完整素材\\老鹰_1.png");
		setimage(40, 40, mapprop_4);
		PIMAGE mapprop_5 = newimage();
		getimage(mapprop_5, "坦克大战完整素材\\老鹰_2.png");
		setimage(40, 40, mapprop_5);

		for (list<mapstr>::iterator it = listmap.begin(); it != listmap.end(); it++)
		{
			switch (it->prop)
			{
			case 0:
				putimage(it->m_x, it->m_y, mapprop_0);
				break;
			case 1:
				putimage(it->m_x, it->m_y, mapprop_1);
				break;
			case 2:
				putimage(it->m_x, it->m_y, mapprop_2);
				break;
			case 4:
				putimage(it->m_x, it->m_y, mapprop_4);
				break;
			case 5:
				putimage(it->m_x, it->m_y, mapprop_5);
				break;
			}
		}

		delimage(mapprop_0);
		delimage(mapprop_1);
		delimage(mapprop_2);
		delimage(mapprop_4);
		delimage(mapprop_5);

	}

	//获取地图容器
	list<mapstr> getmapves()
	{
		return listmap;
	}
};


//坦克父类
class Tank
{
public:
	virtual void move(const list<mapstr>& tempves) = 0;	//坦克移动函数

	int getlauch_x()	//获取子弹x坐标
	{
		return b_m_x;
	}
	int getlauch_y()	//获取子弹y坐标
	{
		return b_m_y;
	}
	void setlauch_xy()	//设置子弹坐标
	{
		b_m_x = m_x + 18;	//重置位置为坦克中间
		b_m_y = m_y + 18;
		key1 = key2;		//key1 = key2避免炮弹一直发射
	}
	int getTank_x()		//获取坦克x坐标
	{
		return m_x;
	}
	int getTank_y()		//获取坦克y坐标
	{
		return m_y;
	}
	char getkey2()		//返回发射时的坦克方向信息
	{
		return key2;
	}

	//坦克攻击子弹位置爆炸
	void exploed()
	{
		PIMAGE explimg_1 = newimage();
		getimage(explimg_1, "坦克大战完整素材\\爆炸效果1.png");
		setimage(10, 10, explimg_1);
		PIMAGE explimg_2 = newimage();
		getimage(explimg_2, "坦克大战完整素材\\爆炸效果2.png");
		setimage(20, 20, explimg_2);
		PIMAGE explimg_3 = newimage();
		getimage(explimg_3, "坦克大战完整素材\\爆炸效果3.png");
		setimage(40, 40, explimg_3);

		PIMAGE explimgarr[3] = { explimg_1, explimg_2, explimg_3 };

		for (int i = 0; i < 3; i++)
		{
			if (key2 == 'd' || key2 == 'a')//根据坦克的攻击朝向确定爆炸的位置
				putimage(b_m_x, b_m_y - 6 * i, explimgarr[i]);
			else
				putimage(b_m_x - 6 * i, b_m_y, explimgarr[i]);

			delay_fps(42);
		}

		delimage(explimg_1);
		delimage(explimg_2);
		delimage(explimg_3);
	}

	//构造函数
	Tank()	
	{
		m_x = 0; m_y = 0;
		m_health = 0; m_damage = 0;
		path_1 = NULL; path_2 = NULL;
		path_3 = NULL; path_4 = NULL;
		b_m_x = 0; b_m_y = 0;
		key1 = '0'; key2 = '0';
	}

protected:
	//从文件中获取坦克图片
	void gettank(const char *path)	
	{
		PIMAGE tankimg = newimage();	//创建图片对象
		getimage(tankimg, path);		//在文件中获取图片到图片对象
		setimage(40, 40, tankimg);		//设置图片对象大小
		putimage(this->m_x, this->m_y, tankimg);//在坐标处输出图片
		delimage(tankimg);				//释放图片对象
	}
	//输出显示坦克
	void printtank(const char key2)
	{
		//根据当前的键值,输出坦克
		switch (key2)
		{
		case 'w':
			gettank(path_1); break;		//输出坦克
		case 's':
			gettank(path_2); break;
		case 'a':
			gettank(path_3); break;
		case 'd':
			gettank(path_4); break;
		}
	}

	//发射子弹
	void launch()
	{
		printtank(key2);
		setfillcolor(WHITE);

		switch (key2)
		{
		case 'w':
			b_m_y -= 10;
			bar(b_m_x, b_m_y, b_m_x + 4, b_m_y + 8);
			break;
		case 'a':
			b_m_x -= 10;
			bar(b_m_x, b_m_y, b_m_x + 8, b_m_y + 4);
			break;
		case 's':
			b_m_y += 10;
			bar(b_m_x, b_m_y, b_m_x + 4, b_m_y + 8);
			break;
		case 'd':
			b_m_x += 10;
			bar(b_m_x, b_m_y, b_m_x + 8, b_m_y + 4);
			break;
		}

		//子弹越界目标则子弹坐标刷新
		if (b_m_x >= 900 || b_m_x <= 0 || b_m_y >= 600 || b_m_y <= 0)
			setlauch_xy();		//重置子弹位置
	}

	int m_x;		//坦克xy坐标
	int m_y;
	int m_health;	//坦克血量
	int m_damage;	//子弹伤害量
	char* path_1;	//四张不同方向的坦克图片,由派生类决定图片路径
	char* path_2;
	char* path_3;
	char* path_4;
	int b_m_x;		//子弹坐标xy
	int b_m_y;
	char key1;		//用于接收键盘信息
	char key2;		//用于存储上一条键值,也是发射时的坦克的朝向

};

//游戏失败结束全局函数  在生命为0 和 基地被攻击时调用
void gameoverfalse()
{
	cleardevice();

	PIMAGE gameoverbackimg = newimage();	
	getimage(gameoverbackimg, "坦克大战完整素材\\游戏结束背景.jpg");
	setimage(900,600,gameoverbackimg);
	putimage(0, 0, gameoverbackimg);	//输出背景图片

	PIMAGE gameoverimg = newimage();
	getimage(gameoverimg, "坦克大战完整素材\\游戏结束.png");
	setimage(200, 200, gameoverimg);
	putimage_withalpha(NULL, gameoverimg, 350, 200);	//透明格式输出游戏结束图片

	delimage(gameoverbackimg);
	delimage(gameoverimg);				//释放内存

	getch();
	getch();
}

//我方坦克,可被操控移动
class TankFriend :public Tank
{
private:
	int Fridienum = 0;
public:
	//构造函数初始化坦克坐标
	TankFriend()
	{
		m_x = 300;		//我方坦克的初始坐标为屏幕中下方
		m_y = 560;
		m_health = 100;	//坦克血量
		m_damage = 90;	//坦克伤害
		b_m_x = m_x + 18;
		b_m_x = m_x + 18;
		path_1 = "坦克大战完整素材\\己方坦克上.png";	//赋值需要将源文件属性语言中符合模式改为否
		path_2 = "坦克大战完整素材\\己方坦克下.png";
		path_3 = "坦克大战完整素材\\己方坦克左.png";
		path_4 = "坦克大战完整素材\\己方坦克右.png";
		key1 = 'w';		//初始化key1用于输出初始的坦克
	}

	int getTankdamage()		//获取坦克伤害
	{
		return m_damage;
	}
	int getTankhealth()		//获取坦克血量
	{
		return m_health;
	}
	void setTankhealth(const int health)	//设置坦克血量
	{
		m_health = health;
	}
	int getFridienumfun()	//获取我方坦克被消灭次数
	{
		return Fridienum;
	}
	
	//坦克被操控移动
	virtual void move(const list<mapstr>& tempves)
	{
		if (key1 != 'j')
			key2 = key1;	  //key2记录上一个key1的值

		if (kbhit())
		{
			//用临时变量接收键值,如果键值为wasdj中的一个则赋给使用的变量
			char tempkey = getch();

			switch (tempkey)
			{
			case 'w': case 'a':
			case 's': case 'd':
			case 'j':
				key1 = tempkey;
				break;
			//接收的键盘值不是wasdj直接return
			default:
				return;
			}

			//判断坦克撞墙情况,坦克撞墙可以改变方向,但不会移动坐标
			for (list<mapstr>::const_iterator it = tempves.begin(); it != tempves.end(); it++)
			{
				switch (tempkey)
				{
				//这里的大于小于号一个都不能错
				case 'w':
					if (
							(
								//判断坦克原xy点
								(m_x >= it->m_x && m_x < it->m_x + 20) && (m_y - 20 == it->m_y) ||

								//判断坦克右xy点
								(m_x + 40 > it->m_x&& m_x + 40 <= it->m_x + 20) && (m_y - 20 == it->m_y)
							)
								//判断方块属性
								&& (it->prop == 0 || it->prop == 1)
									
								//判断地图边界范围
								|| (m_y - 20 < 0)
						)
						return;
					break;
				case 'a':
					if (
							(
								//判断坦克原xy点
								(m_y >= it->m_y && m_y < it->m_y + 20) && (m_x - 20 == it->m_x) ||

								//判断坦克右xy点
								(m_y + 40 > it->m_y && m_y + 40 <= it->m_y + 20) && (m_x - 20 == it->m_x)
							)
								//方块属性
								&& (it->prop == 0 || it->prop == 1)

								//判断地图边界范围
								|| (m_x - 20 < 0)
						)
						return;
					break;
				case 's':
					if (
							(
								//判断坦克原xy点
								(m_x >= it->m_x && m_x < it->m_x + 20) && (m_y + 40 == it->m_y) ||

								//判断坦克右xy点
								(m_x + 40 > it->m_x&& m_x + 40 <= it->m_x + 20) && (m_y + 40 == it->m_y)
							)
								//判断方块属性
								&& (it->prop == 0 || it->prop == 1)

								//判断地图边界范围
								|| (m_y + 60 > 600)
						)
						return;
					break;
				case 'd':
					if (
							(
								//判断坦克原xy点
								(m_y >= it->m_y && m_y < it->m_y + 20) && (m_x + 40 == it->m_x) ||

								//判断坦克右xy点
								(m_y + 40 > it->m_y&& m_y + 40 <= it->m_y + 20) && (m_x + 40 == it->m_x)
							)
								//方块属性
								&& (it->prop == 0 || it->prop == 1)

								//判断地图边界范围
								|| (m_x + 60 > 900)
						)
						return;
					break;
				}
			}

			//根据key1值修改坦克坐标
			switch (key1)
			{
			case 'w':
				m_y -= 20; break;
			case 'a':
				m_x -= 20; break;
			case 's':
				m_y += 20; break;
			case 'd':
				m_x += 20; break;
			}
		}

		//如果键值为j则发射炮弹,如果键值为wasd则移动坦克
		if (key1 == 'j')
			launch();
		else
		{
			printtank(key1);		//根据键值输出显示坦克
			b_m_x = m_x + 18;		//移动时也重置子弹坐标
			b_m_y = m_y + 18;		//这里key1值不能重置为key2值
		}

		//如果我军坦克被消灭,则被消灭次数+1,并重置坦克
		if (m_health <= 0)		
		{
			Fridienum++;
			m_x = 300;	//坐标
			m_y = 560;
			m_health = 100;	//血量
		}
	}
};

//统计所有敌军坦克次数全局变量
int Endienum;

//敌军坦克
class TankEnemy :public Tank		
{
private:
	int pathsch;	//路线方案
	int contdir;
	bool Entankdie = true;	//标记敌军坦克的死亡状态

public:
	//构造函数接收初始坦克坐标
	TankEnemy(const int x ,const int y, const int pathsch)			//构造函数初始化坦克坐标
	{
		m_x = x;			//敌方坦克初始坐标
		m_y = y;
		b_m_x = m_x + 18;	//坦克子弹坐标
		b_m_x = m_x + 18;
		m_health = 300;		//坦克血量
		m_damage = 90;		//坦克伤害
		contdir = 0;
		this->pathsch = pathsch;	//路线
		path_1 = "坦克大战完整素材\\敌方坦克上.png";	//赋值需要将源文件属性语言中符合模式改为否
		path_2 = "坦克大战完整素材\\敌方坦克下.png";
		path_3 = "坦克大战完整素材\\敌方坦克左.png";
		path_4 = "坦克大战完整素材\\敌方坦克右.png";

		gettank(path_1);//输出一个坦克图片
	}

	int getTankdamage()		//获取坦克伤害
	{
		return m_damage;
	}
	int getTankhealth()		//获取坦克血量
	{
		return m_health;
	}
	void setTankhealth(const int health)	//设置坦克血量
	{
		m_health = health;
	}
	bool getEntadist()						//获取坦克的死亡状态
	{
		return Entankdie;
	}
	void setpathsch(const int tanknum)						//修改坦克行动路线
	{
		switch (tanknum)	//判断坦克编号
		{
		case 1:
			pathsch = 5;	//坦克1路线切换为路线2
			break;
		case 2:
			pathsch = 6;
			break;
		case 3:
			pathsch = 7;
			break;
		case 4:
			pathsch = 8;
			break;
		}
	}

	//重置坦克
	void setEntank(const int tanknum)
	{
		if (Entankdie == false && (pathsch == 5 || pathsch == 6 || pathsch == 7 || pathsch == 8))
			return;		//如果这个坦克的路线已经被修改过,且再次死亡,则不再重置

		switch (tanknum)
		{
		case 1:
			m_x = 200, m_y = 40;
			contdir = 2;
			break;
		case 2:
			m_x = 720, m_y = 120;
			contdir = 3;
			break;
		case 3:
			m_x = 560, m_y = 120;
			contdir = 2;
			break;
		case 4:
			m_x = 80, m_y = 360;
			contdir = 2;
		}
		m_health = 300;
		Entankdie = true;
	}

	//坦克1第二路线
	//直接攻击基地
	void pathschfun5_1_2()
	{
		static bool temp = true;	//临时变量用作标记

		if(temp == true)
			contdir = 2;

		if (m_y == 560 && temp == true)		//往右
			contdir = 4;

		if (m_y == 560 && m_x == 240)
		{
			m_y = 560, m_x = 240;
			contdir = 0;
			temp = false;
		}
	}

	//坦克2路线2
	void pathschfun6_2_2()
	{
		//720, 120
		//需要改变两次方向
		static bool temp = true;
		static bool temp2 = true;

		if (temp == true && temp2 == true)
			contdir = 3;	//往左

		if (m_x == 200 && temp == true && temp2 == true)		//往下
			contdir = 2;

		if (m_x == 200 && m_y == 560 && temp == true)
		{
			contdir = 4;		//往右
			temp2 = false;
		}

		if (m_y == 560 && m_x == 280)
		{
			m_y = 560, m_x = 280;
			contdir = 0;
			temp = false;
		}
	}

	//坦克3路线2
	void pathschfun7_3_2()
	{
		static bool temp = true;
		if (temp == true)
			contdir = 2;	//往下

		if (m_y == 560 && temp == true)		//往左
			contdir = 3;

		if (m_y == 560 && m_x == 480)
		{
			m_y = 560, m_x = 480;
			contdir = 0;
			temp = false;
		}
	}

	//坦克4路线2
	void pathschfun8_4_2()
	{
		static bool temp = true;
		if(temp == true)
			contdir = 2;

		if (m_y == 560 && temp == true)
			contdir = 4;

		if (m_x == 200 && m_y == 560)
		{
			m_x = 200, m_y = 560;
			contdir = 0;
			temp = false;
		}
	}
	
	//正常路线1
	void pathschfun_1()
	{
		static bool temp  = false;    //临时变量辅助控制坦克行走路线

		if (m_y == 480 && m_x == 200 && temp == true)			//上
		{
			b_m_x = m_x + 18;				//重置子弹位置为坦克中间
			b_m_y = m_y + 18;
			contdir = 1;
			return;
		}
		else if (m_y == 40 && m_x == 200)						//下
		{
			b_m_x = m_x + 18;
			b_m_y = m_y + 18;
			contdir = 2;
			temp = false;
			return;
		}
		else if (m_y == 480 && m_x == 200 && temp == false)		//右
		{
			b_m_x = m_x + 18;
			b_m_y = m_y + 18;
			contdir = 4;
			temp = true;
			return;
		}
		else if (m_x == 700 && m_y == 480)						//左
		{
			b_m_x = m_x + 18;
			b_m_y = m_y + 18;
			contdir = 3;
			return;
		}
	}

	//正常路线2
	void pathschfun_2()
	{
		if (m_x == 720)
		{
			b_m_x = m_x + 18;				
			b_m_y = m_y + 18;
			contdir = 3;
			return;
		}
		if (m_x <= 140)
		{
			b_m_x = m_x + 18;
			b_m_y = m_y + 18;
			contdir = 4;
			return;
		}
	}

	//正常路线3
	void pathschfun_3()
	{
		if (m_y == 120)
		{
			b_m_x = m_x + 18;
			b_m_y = m_y + 18;
			contdir = 2;
			return;
		}
		if (m_y >= 480)
		{
			b_m_x = m_x + 18;
			b_m_y = m_y + 18;
			contdir = 1;
			return;
		}
	}

	//正常路线4
	void pathschfun_4()
	{
		if (m_y == 360)
		{
			b_m_x = m_x + 18;
			b_m_y = m_y + 18;
			contdir = 2;
			return;
		}
		if (m_y >= 560)
		{
			b_m_x = m_x + 18;
			b_m_y = m_y + 18;
			contdir = 1;
			return;
		}
	}
	
	//敌军坦克自动移动
	virtual void move(const list<mapstr>& tempves)
	{
		//根据contdir值,向不同方向移动
		switch (contdir)
		{
		case 1:
			key2 = 'w';			//方向
			gettank(path_1);	//坦克图片
			m_y -= 4;
			break;
		case 2:
			key2 = 's';
			gettank(path_2);
			m_y += 4;
			break;
		case 3:
			key2 = 'a';
			gettank(path_3);
			m_x -= 4;
			break;
		case 4:
			key2 = 'd';
			gettank(path_4);
			m_x += 4;
			break;
		}

		launch();	//发射子弹

		//不同pathsch不同路线  一个坦克两条路线
		switch (pathsch)
		{
		case 1: pathschfun_1(); break;
		case 2: pathschfun_2(); break;
		case 3: pathschfun_3(); break;
		case 4: pathschfun_4(); break;
		case 5: pathschfun5_1_2(); break;
		case 6: pathschfun6_2_2(); break;
		case 7: pathschfun7_3_2(); break;
		case 8: pathschfun8_4_2();
		}


		//敌军坦克被消灭
		//如果坦克血量小于等于0,则将坦克从界面内移除
		if (m_health <= 0)
		{
			Endienum++;			//敌军坦克被消灭次数自增
			Entankdie = false;	//死亡状态为false
			m_x = -40,m_y = -40;//坦克被移除至页面外
			b_m_x = m_x, b_m_y = m_y;//子弹跟随坦克
		}

		
	}
};

//敌军坦克数量
const int N = 4;

//子弹命中检测
bool hittest(TankFriend& tank_f, TankEnemy* Etankarr, list<mapstr>& listmap)	//参数:我方坦克对象,敌军坦克对象数组,地图list容器
{
	const int tanfirlau_x = tank_f.getlauch_x();	//友军坦克子弹x坐标
	const int tanfirlau_y = tank_f.getlauch_y();	//友军坦克子弹y坐标
	const int firtank_x = tank_f.getTank_x();		//友军坦克x坐标
	const int firtank_y = tank_f.getTank_y();		//友军坦克y坐标
	const int tankfirdam = tank_f.getTankdamage();	//友军坦克伤害
	const int tankfirhea = tank_f.getTankhealth();	//友军坦克血量

	for (int i = 0; i < N; i++)
	{
		//发射子弹需要判断两个点
		//如果友军子弹和敌军坦克重合,敌军坦克血量减少,且友军坦克子弹坐标重置
		if ((tanfirlau_x >= Etankarr[i].getTank_x() && tanfirlau_x <= Etankarr[i].getTank_x() + 40 && 
			tanfirlau_y >= Etankarr[i].getTank_y() && tanfirlau_y <= Etankarr[i].getTank_y() + 40) ||
			(tanfirlau_x + 4 >= Etankarr[i].getTank_x() && tanfirlau_x <= Etankarr[i].getTank_x() + 4 + 40 && 
				tanfirlau_y >= Etankarr[i].getTank_y() + 4 && tanfirlau_y + 4 <= Etankarr[i].getTank_y() + 40))
		{
			Etankarr[i].setTankhealth(Etankarr[i].getTankhealth() - tankfirdam);	//血量减少
			tank_f.exploed();			//友方坦克攻击导致子弹遇到对方的位置爆炸
			tank_f.setlauch_xy();								//友军的炮弹坐标重置
		}
		//如果敌军子弹和友军坦克重合,友军坦克血量减少,且敌军坦克子弹坐标重置
		if ((Etankarr[i].getlauch_x() >= firtank_x && Etankarr[i].getlauch_x() <= firtank_x + 40 && 
			Etankarr[i].getlauch_y() >= firtank_y && Etankarr[i].getlauch_y() <= firtank_y + 40) ||
			(Etankarr[i].getlauch_x() + 4 >= firtank_x && Etankarr[i].getlauch_x() + 4 <= firtank_x + 40 && 
				Etankarr[i].getlauch_y() + 4 >= firtank_y && Etankarr[i].getlauch_y() + 4 <= firtank_y + 40))
		{
			tank_f.setTankhealth(tankfirhea - Etankarr[i].getTankdamage());		//友军坦克本身血量 - 敌军坦克伤害
			Etankarr[i].exploed();
			Etankarr[i].setlauch_xy();											//敌军的炮弹坐标重置
		}
	

		//判断墙的状态
		//包括我军坦克和敌军坦克子弹和墙的状态
		for (list<mapstr>::iterator it = listmap.begin(); it != listmap.end(); it++)
		{
			//子弹碰到墙壁需要判断两个点
			if ((tank_f.getlauch_x() >= it->m_x && tank_f.getlauch_x() <= it->m_x + 20 &&
				tank_f.getlauch_y() >= it->m_y && tank_f.getlauch_y() <= it->m_y + 20) ||
				(tank_f.getlauch_x() + 4 >= it->m_x && tank_f.getlauch_x() + 4 <= it->m_x + 20 &&
				tank_f.getlauch_y() + 4 >= it->m_y && tank_f.getlauch_y() + 4 <= it->m_y + 20))
			{
				switch (it->prop)
				{
				case 0:		//砖块可以被删除
					tank_f.exploed();		//子弹处发生爆炸
					tank_f.setlauch_xy();	//子弹重置
					listmap.erase(it);		//删除被子弹击中的墙壁数据
					break;
				case 1:		//铁块会爆炸不会被删除
					tank_f.exploed();		//子弹处发生爆炸
					tank_f.setlauch_xy();	//子弹重置
					break;
				case 2:		//草块不会有作用
					break;
				case 4:
					mapstr temp;
					temp.m_x = it->m_x;
					temp.m_y = it->m_y;
					temp.prop = 5;
					listmap.insert(it, temp);
					listmap.erase(it);		//老鹰被攻击游戏结束
					return true;
				}
				//最后break
				break;
			}

			if ((Etankarr[i].getlauch_x() >= it->m_x && Etankarr[i].getlauch_x() <= it->m_x + 20 &&
				Etankarr[i].getlauch_y() >= it->m_y && Etankarr[i].getlauch_y() <= it->m_y + 20) ||
				(Etankarr[i].getlauch_x() + 4 >= it->m_x && Etankarr[i].getlauch_x() + 4 <= it->m_x + 20 &&
					Etankarr[i].getlauch_y() + 4 >= it->m_y && Etankarr[i].getlauch_y() + 4 <= it->m_y + 20))
			{
				switch (it->prop)
				{
				case 0:		//砖块可以被删除
					Etankarr[i].exploed();		//子弹处发生爆炸
					Etankarr[i].setlauch_xy();	//子弹重置
					listmap.erase(it);		//删除被子弹击中的墙壁数据
					break;
				case 1:		//铁块会爆炸不会被删除
					Etankarr[i].exploed();		//子弹处发生爆炸
					Etankarr[i].setlauch_xy();	//子弹重置
					break;
				case 2:		//草块不会有作用
					break;
				case 4:
					mapstr temp;
					temp.m_x = it->m_x;
					temp.m_y = it->m_y;
					temp.prop = 5;
					listmap.insert(it, temp);
					listmap.erase(it);
					return true;
				}
				//最后break
				break;
			}
		}
	}
	return false;
}

//游戏开始界面
void initgamebegin()
{
	//开始背景
	PIMAGE gabegbaimg = newimage();
	getimage(gabegbaimg,"坦克大战完整素材\\开始游戏背景.jpg");
	setimage(1000,600,gabegbaimg);
	putimage(0, 0, gabegbaimg);
	//开始按钮
	PIMAGE gabegimg = newimage();
	getimage(gabegimg, "坦克大战完整素材\\开始游戏.png");
	setimage(290, 210, gabegimg);
	putimage_withalpha (NULL, gabegimg, 305, 440);

	setfont(120,0,"楷体");				//设置字号,字体
	setcolor(YELLOW);					//设置文字颜色
	setbkmode(1);						//文字背景色透明
	outtextxy(210, 100, "坦克大战");	//输出文字
	
	mouse_msg msg;		//接收开始游戏的鼠标信息

	while (true)
	{
		msg = getmouse();

		if (msg.is_left())
			if (msg.x >= 305 && msg.y >= 440 && msg.x <= 305 + 290 && msg.y <= 440 + 210)
				break;

		delay_fps(50);
	}

}

//游戏胜利结束,全局函数
void gameovertrue()
{
	cleardevice();

	PIMAGE gameoverbackimg = newimage();
	getimage(gameoverbackimg, "坦克大战完整素材\\游戏胜利结束背景.jpg");
	setimage(1000, 600, gameoverbackimg);
	putimage(0, 0, gameoverbackimg);	//输出背景图片

	PIMAGE gameoverimg = newimage();
	getimage(gameoverimg, "坦克大战完整素材\\胜利文字.png");
	setimage(206, 107, gameoverimg);
	putimage_withalpha(NULL, gameoverimg, 347, 220);	//透明格式输出游戏结束图片

	delimage(gameoverbackimg);
	delimage(gameoverimg);				//释放内存

	getch();
	getch();
}


//主函数
int main()
{
	initgraph(900, 600, INIT_RENDERMANUAL);	//初始化图形界面
	setcaption("C++ EGE坦克大战");			//设置窗口标题

	initgamebegin();						//游戏开始界面

	TankFriend tank_f;						//我方坦克
	TankEnemy tank_e_1(200, 40, 1);			//敌方坦克 1
	TankEnemy tank_e_2(720, 120, 2);		//敌方坦克 2
	TankEnemy tank_e_3(560, 120, 3);		//敌方坦克 3
	TankEnemy tank_e_4(80, 360, 4);			//敌方坦克 4

	//敌军坦克数组
	TankEnemy Etankarr[N] = { tank_e_1, tank_e_2,tank_e_3,tank_e_4 };

	Mymap map_1;	//地图

	//获取地图信息
	list<mapstr> listmap = map_1.getmapves();

	bool gameoverstat = false;		//判断游戏结束状态变量,默认失败
	bool basestat = false;			//判断基地老鹰的状态,为真则游戏失败

	//游戏循环
	while (true)
	{
		cleardevice();				//清屏

		//三条生命  被消灭三次时结束游戏
		 if (tank_f.getFridienumfun() < 3) 
			 tank_f.move(listmap);
		 else break;

		//敌军坦克数组循环
		for (int i = 0; i < N; i++)
		{
			if(Etankarr[i].getEntadist() == true)	//坦克必须存活时才会调用移动函数
				Etankarr[i].move(listmap);			//敌方坦克
			else
			{
				switch (Endienum)
				{
				case 3:								//坦克死亡时,且敌军总被消灭次数为3时,已被消灭坦克复活
					Etankarr[i].setEntank(i + 1);	//重置已坦克被消灭
					break;
				case 4:
				case 6:
				case 8:
				case 10:
					Etankarr[i].setEntank(i + 1);	//重置坦克
					Etankarr[i].setpathsch(i + 1);	//修改坦克路线
				}
			}
		}

		map_1.printmap(listmap);			//输出地图

		basestat = hittest(tank_f, Etankarr ,listmap);	//子弹命中坦克检测

		if (basestat) break;				//如果basestat为true则游戏按失败break

		if (Endienum > 10)					//消灭敌军达10则游戏胜利
		{
			gameoverstat = true;
			break;
		}

		delay_fps(62);
	}

	//根据游戏结束状态,调用结束函数
	gameoverstat ? gameovertrue(): gameoverfalse();		//游戏结束

	return 0;
}

//设置图片宽高全局函数
void setimage(int pwidth, int pheight, PIMAGE img_1)
{
	int whidth = getwidth(img_1), height = getheight(img_1);//获取当前img图像对象的宽高

	PIMAGE img_2 = newimage(pwidth, pheight);           //创建一个新的图像对象,这个新的图像对象的宽高为
														//要重新设置的图像的宽高

	putimage(img_2, 0, 0, pwidth, pheight, img_1, 0, 0, whidth, height);	//将原本img中的图像拉伸绘制到img_2中

	getimage(img_1, img_2, 0, 0, pwidth, pheight);      //img再获取img_2中的图像

	delimage(img_2);  //使用完毕将释放掉
}

不足之处:
参照标准的坦克大战,子弹在攻击砖块时,如果子弹正好打中两个砖块,则两个砖块同时被消灭,这个效果我在程序中做不出来。只能是用一个一个地消灭代替了。
在按下键键值不是wasdj时和坦克碰到墙壁时坦克会闪的问题,也暂时没有找到解决办法。
因为初学C++,所以我在类和对象的使用上面还有着很多很多的缺陷和不规范的地方。
还有关于地图的问题,因为我没有经验,所以不知道该怎么简便地创造一个游戏地图,在刚开始的时候还在为用什么实现地图而犹豫过,最后还是选择了list容器逐个将地图元素塞进去,因为考虑到list容器插入和删除数据很快。
我知道在程序中很多地方我都写的极为地不合理,以至于程序运行效率非常低(从我的CPU占用看出来的),但是我会继续努力,继续学习,争取早日解决这些问题。

欢迎大家提出批评和建议。


感谢大家的支持。

原创文章 20 获赞 24 访问量 8355

猜你喜欢

转载自blog.csdn.net/qq_46239972/article/details/104566928