C++ EGE 实现坦克大战小游戏
因为有过一次用EGE写小游戏的经验,所以这一次写坦克大战快了很多。并且使用对象编程也简化了很多编程时繁琐的步骤。
写出坦克大战使我在学习编程的道路上又迈出了一大步。
如果您需要图片素材的,我可以单独发给您。
技术环节:
编译环境:Windows VS
需求:
控制坦克移动发射炮弹,炮弹可以消灭敌军坦克,且可以消灭砖块。坦克遇到方块会被挡住。敌军消灭我军三次或基地被毁则游戏失败,共摧毁十次敌方坦克游戏胜利。
思路:
先写出坦克的父类,我方坦克类和敌方坦克类继承坦克父类,实例化我方坦克和敌方坦克。地图使用list容器存储。
在代码注释中标注了每一步是怎么实现的。
注意:
因为我在程序中用了一些不规范的写法,所以要在VS中正常编译运行,需要右键源文件->属性->C/C+±>符合模式,改为否。
包含<graphics.h>图形库需要提前配置EGE图形库。
如要在其他graphics图形库下编译,可能需要修改某些地方。
运行效果:
#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]);elseputimage(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;//子弹坐标xyint 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直接returndefault: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路线切换为路线2break;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路线2void 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路线2void 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路线2void 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;}}//正常路线1void 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;}}//正常路线2void 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;}}//正常路线3void 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;}}//正常路线4void 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;//死亡状态为falsem_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;}//最后breakbreak;}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;}//最后breakbreak;}}}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);//敌方坦克 1TankEnemy tank_e_2(720, 120, 2);//敌方坦克 2TankEnemy tank_e_3(560, 120, 3);//敌方坦克 3TankEnemy 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则游戏按失败breakif (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占用看出来的),但是我会继续努力,继续学习,争取早日解决这些问题。
欢迎大家提出批评和建议。
感谢大家的支持。