简易的射击坦克小游戏(easyx)的而从开发
引言
在网上看到了一个利用easyx图形库制作的简易射击游戏,并下载源码体验了一下之后发现存在以下缺点:
1.鼠标点击之后发射的激光速度很慢,有一种很卡的感觉,影响游戏体验感。
2.玩家移动过于缓慢,同样给玩家一种很卡的感觉。
3.对于发射激光的图形即飞机,采用的是easyx构造的图形,飞机模型不够形象美观。
4.对于激光击落每一个障碍物之后,障碍物就直接消失了,缺少得分,缺乏趣味性。
5.对于代码还有一个bug,当飞机撞向障碍物的时候,理应提示失败不能撞到,但装上去之后并没有什么变化。
6.只有一个模式比较单调
原程序代码
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <iostream> #include <graphics.h> #include <windows.h> #include <time.h> #include <Mmsystem.h> #include <conio.h> using namespace std; struct TANK { int x1; int y1; //定义坦克出来的位置 }; TANK tank[50]; int i = 0; int tlong = 30; // 定义坦克的长度 int thig = 30; //坦克宽度 int x2 = 50; int y2 = 375; //玩家的位置坐标(x2,y2) int ky; //从键盘得到的命令 int temp_x2 = 50; int temp_y2 = 375; MOUSEMSG m; //定义鼠标事件 void drawtank() //画出坦克 { setcolor(RED); setfillcolor(RED); rectangle(tank[i].x1, tank[i].y1, tank[i].x1 + tlong, tank[i].y1 + thig); fillrectangle(tank[i].x1, tank[i].y1, tank[i].x1 + tlong, tank[i].y1 + thig); setlinestyle(PS_SOLID, 5); line(tank[i].x1 + tlong / 2, tank[i].y1 + tlong, tank[i].x1 + tlong / 2, tank[i].y1 + tlong + 20); //绘制炮管 } //记住炮口坐标 (tank[i].x1 + tlong/2, tank[i].y1 + tlong+20) void enemyfire() //模拟敌方开火 { int b = 0; //炮弹增加值 for (int a = 0; a < 10; a++) { b = b + 40; setcolor(YELLOW); setlinestyle(PS_SOLID, 8); circle(tank[i].x1 + tlong / 2, tank[i].y1 + tlong + 20 + b, 2); Sleep(10); setcolor(WHITE); setlinestyle(PS_SOLID, 8); circle(tank[i].x1 + tlong / 2, tank[i].y1 + tlong + 20 + b, 2); } } void hideplayer() //让玩家在移动前被覆盖,即掩码图 { setcolor(WHITE); setfillcolor(WHITE); circle(temp_x2, temp_y2, 8); fillcircle(temp_x2, temp_y2, 8); } void drawplayer() //画出玩家新的位置,达到使其移动的效果 { setcolor(GREEN); setfillcolor(GREEN); circle(x2, y2, 8); fillcircle(x2, y2, 8); } void playermove() //定义玩家角色 { int dis = 50; //增加玩家移动的距离为50 //记录玩家角色之前所在的坐标 setcolor(GREEN); if (_kbhit()) { ky = _getch(); switch (ky) { case 97: //a temp_x2 = x2; temp_y2 = y2; //用temp_x2,y2保存该点之前的坐标,即掩码图坐标 hideplayer(); x2 = x2 - dis; drawplayer(); break; case 100: //d temp_x2 = x2; temp_y2 = y2; //用temp_x2,y2保存该点之前的坐标,即掩码图坐标 hideplayer(); x2 = x2 + dis; drawplayer(); break; case 115: //s temp_x2 = x2; temp_y2 = y2; //用temp_x2,y2保存该点之前的坐标,即掩码图坐标 hideplayer(); y2 = y2 + dis; drawplayer(); break; case 119: //w temp_x2 = x2; temp_y2 = y2; //用temp_x2,y2保存该点之前的坐标,即掩码图坐标 hideplayer(); y2 = y2 - dis; drawplayer(); break; } } } void startup() { for (int i = 0; i < 50; i++) { tank[i].x1 = rand() % 920; tank[i].y1 = rand() % 593; } } void playerfire() //设置玩家开火,x2,y2为玩家坐标!!记住!! { //发射火箭弹QAQ!!!! m = GetMouseMsg(); switch (m.uMsg) { case WM_LBUTTONDOWN: setcolor(YELLOW); setlinestyle(PS_SOLID, 2); line(x2, y2, m.x, m.y); Sleep(100); //减少激光显示的间隔时间 setcolor(WHITE); setlinestyle(PS_SOLID, 8); line(x2, y2, m.x, m.y); setfillcolor(WHITE); solidcircle(m.x, m.y, 40); break; case WM_RBUTTONDOWN: int sl = 10; int sr = 30; //定义掩体的长度 setcolor(BLUE); rectangle(m.x + sr, m.y + sl, m.x - sr, m.y - sl); setfillcolor(BLUE); fillrectangle(m.x + sr, m.y + sl, m.x - sr, m.y - sl); break; } } int dis; void surface() { cout << endl << endl << endl << endl << " 坦克小游戏" << endl; cout << "游戏说明:" << endl; cout << " 按“ASDW”进行上下左右移动 ,按鼠标左键 点击 目标坦克开炮,鼠标右键释放掩体 " << endl << endl; cout << " 选择游戏难度 输入(1)普通敌人,(2)一般敌人,(3)冷酷敌人" << endl << endl; cout << " ----------------------------输入数字,选择难度,按ENTER进入游戏-------------------------------- " << endl; cin >> dis; } int main() { int dis2; surface(); if (dis == 1) { dis2 = 100; } if (dis == 2) { dis2 = 50; } if (dis == 3) { dis = 20; } else { dis = 100; } int windowwid = 920; int windowhig = windowwid * 0.618; initgraph(windowwid, windowhig); setbkcolor(WHITE); cleardevice(); for (int k = 0;; k++) { if (k % dis == 0) { startup(); drawtank(); enemyfire(); } drawplayer(); playermove(); playerfire(); } closegraph(); return 0; }
由绿色源点发射激光
对于上述问题的细化改进
1.鼠标点击之后发射的激光速度很慢
解决方法:发现控制激光发射使用的是sleep函数,发现其代码设置为800,于是将其减少到100即可很快发射
sleep(100)
2.玩家移动过于缓慢
解决方法:尝试增加玩家移动的距离(比如将dis的值调整为更大的数值)或者减少移动时的间隔时间(比如减小Sleep函数的参数)来加快玩家角色的移动速度。这样就可以让玩家角色在按下移动键后更快地移动到新的位置。不过需要注意的是,移动速度过快可能会使得操作变得更具挑战性,需要设置合理的数值。
void hideplayer() //让玩家在移动前被覆盖,即掩码图 { setcolor(WHITE); setfillcolor(WHITE); circle(temp_x2, temp_y2, 8); fillcircle(temp_x2, temp_y2, 8); } void drawplayer() //画出玩家新的位置,达到使其移动的效果 { setcolor(GREEN); setfillcolor(GREEN); circle(x2, y2, 8); fillcircle(x2, y2, 8); }
3.飞机模型不够形象美化
通过修改图标的方式来个性化你的应用程序,your_icon.ico
就是图标文件所在的路径
initgraph(640, 480); // 初始化图形窗口 // 加载自定义图标 IMAGE icon; loadimage(&icon, _T("your_icon.ico")); // 设置窗口图标 HWND hwnd = GetHWnd(); SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon.getHBITMAP()); // 绘制一些内容 setbkcolor(WHITE); cleardevice(); setcolor(BLACK); outtextxy(100, 100, "Custom Icon Example"); Sleep(5000); // 等待一段时间 closegraph(); // 关闭图形窗口
4.设置得分
hitObstacle()
函数用于增加得分,enemyHit()
函数模拟了敌方坦克被击中时的效果,并在其中调用了 hitObstacle()
函数来增加得分
void hitObstacle() { score += 10; // 每次击落障碍物增加10分 std::cout << "得分 +10! 当前总得分: " << score << std::endl; } // 敌方坦克被击中时调用,模拟击中效果并增加得分 void enemyHit() { // 模拟击中效果 std::cout << "敌方坦克被击中!" << std::endl; // 增加得分 hitObstacle(); // 其他处理逻辑 } int main() { // 游戏主循环 while (true) { // 检测玩家操作、敌方坦克移动等游戏逻辑 // 假设玩家击中了敌方坦克 enemyHit(); // 其他游戏逻辑 // 游戏结束条件判断等 // 示例代码结束 } return 0;
5.不能碰到障碍物
isCollisionDetected
函数用于检测飞机与障碍物是否发生碰撞,如果检测到碰撞,则调用 gameOver
函数来处理游戏失败的逻辑
bool isCollisionDetected(int planeX, int planeY, int obstacleX, int obstacleY) { // 进行碰撞检测的逻辑判断,比如计算飞机与障碍物之间的距离,判断是否小于某个阈值 int distance = abs(planeX - obstacleX) + abs(planeY - obstacleY); if (distance < 10) { return true; // 碰撞发生 } else { return false; // 没有发生碰撞 } } void gameOver() { // 游戏失败的处理逻辑 std::cout << "游戏失败,飞机撞到了障碍物!" << std::endl; // 其他处理逻辑,比如显示得分等 exit(0); // 退出游戏 } int main() { int planeX = 100; // 飞机的X坐标 int planeY = 100; // 飞机的Y坐标 int obstacleX = 105; // 障碍物的X坐标 int obstacleY = 105; // 障碍物的Y坐标 // 游戏主循环 while (true) { // 检测玩家操作、飞机移动等游戏逻辑 // 进行碰撞检测 if (isCollisionDetected(planeX, planeY, obstacleX, obstacleY)) { gameOver(); // 发生碰撞,游戏结束 } // 其他游戏逻辑 // 示例代码结束 } return 0; }
6.设置多个模式
设置简单困难模式,其不同之处在于障碍物的出现频率,难度越高频率也越高,只需对不同模式的sleep函数进行调节
完整代码
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <iostream> #include <graphics.h> #include <windows.h> #include <time.h> #include <Mmsystem.h> #include <conio.h> using namespace std; struct TANK { int x1; int y1; //定义坦克出来的位置 }; TANK tank[50]; int i = 0; int tlong = 30; // 定义坦克的长度 int thig = 30; //坦克宽度 int x2 = 50; int y2 = 375; //玩家的位置坐标(x2,y2) int ky; //从键盘得到的命令 int temp_x2 = 50; int temp_y2 = 375; MOUSEMSG m; //定义鼠标事件 IMAGE img; // 图片对象 void drawtank() //画出坦克 { setcolor(RED); setfillcolor(RED); rectangle(tank[i].x1, tank[i].y1, tank[i].x1 + tlong, tank[i].y1 + thig); fillrectangle(tank[i].x1, tank[i].y1, tank[i].x1 + tlong, tank[i].y1 + thig); setlinestyle(PS_SOLID, 5); line(tank[i].x1 + tlong / 2, tank[i].y1 + tlong, tank[i].x1 + tlong / 2, tank[i].y1 + tlong + 20); //绘制炮管 } //记住炮口坐标 (tank[i].x1 + tlong/2, tank[i].y1 + tlong+20) void enemyfire() //模拟敌方开火 { int b = 0; //炮弹增加值 for (int a = 0; a < 10; a++) { b = b + 40; setcolor(YELLOW); setlinestyle(PS_SOLID, 8); circle(tank[i].x1 + tlong / 2, tank[i].y1 + tlong + 20 + b, 2); Sleep(10); setcolor(WHITE); setlinestyle(PS_SOLID, 8); circle(tank[i].x1 + tlong / 2, tank[i].y1 + tlong + 20 + b, 2); } } void hideplayer() //让玩家在移动前被覆盖,即掩码图 { setcolor(WHITE); setfillcolor(WHITE); circle(temp_x2, temp_y2, 8); fillcircle(temp_x2, temp_y2, 8); } void drawplayer() //画出玩家新的位置,达到使其移动的效果 { putimage(x2, y2, &img); // 显示玩家图片 } void playermove() //定义玩家角色 { int dis = 50; //增加玩家移动的距离为50 //记录玩家角色之前所在的坐标 if (_kbhit()) { ky = _getch(); switch (ky) { case 97: //a temp_x2 = x2; temp_y2 = y2; //用temp_x2,y2保存该点之前的坐标,即掩码图坐标 hideplayer(); x2 = x2 - dis; drawplayer(); break; case 100: //d temp_x2 = x2; temp_y2 = y2; //用temp_x2,y2保存该点之前的坐标,即掩码图坐标 hideplayer(); x2 = x2 + dis; drawplayer(); break; case 115: //s temp_x2 = x2; temp_y2 = y2; //用temp_x2,y2保存该点之前的坐标,即掩码图坐标 hideplayer(); y2 = y2 + dis; drawplayer(); break; case 119: //w temp_x2 = x2; temp_y2 = y2; //用temp_x2,y2保存该点之前的坐标,即掩码图坐标 hideplayer(); y2 = y2 - dis; drawplayer(); break; } } } void startup() { for (int i = 0; i < 50; i++) { tank[i].x1 = rand() % 920; tank[i].y1 = rand() % 593; } } void playerfire() //设置玩家开火,x2,y2为玩家坐标!!记住!! { //发射火箭弹QAQ!!!! m = GetMouseMsg(); switch (m.uMsg) { case WM_LBUTTONDOWN: setcolor(YELLOW); setlinestyle(PS_SOLID, 2); line(x2, y2, m.x, m.y); Sleep(100); //减少激光显示的间隔时间 setcolor(WHITE); setlinestyle(PS_SOLID, 8); line(x2, y2, m.x, m.y); setfillcolor(WHITE); solidcircle(m.x, m.y, 40); break; case WM_RBUTTONDOWN: int sl = 10; int sr = 30; //定义掩体的长度 setcolor(BLUE); rectangle(m.x + sr, m.y + sl, m.x - sr, m.y - sl); setfillcolor(BLUE); fillrectangle(m.x + sr, m.y + sl, m.x - sr, m.y - sl); break; } } int dis; void surface() { cout << endl << endl << endl << endl << " 坦克小游戏" << endl; cout << "游戏说明:" << endl; cout << " 按“ASDW”进行上下左右移动 ,按鼠标左键 点击 目标坦克开炮,鼠标右键释放掩体 " << endl << endl; cout << " 选择游戏难度 输入(1)普通敌人,(2)一般敌人,(3)冷酷敌人" << endl << endl; cout << " ----------------------------输入数字,选择难度,按ENTER进入游戏-------------------------------- " << endl; cin >> dis; } int main() { int dis2; surface(); if (dis == 1) { dis2 = 100; } if (dis == 2) { dis2 = 50; } if (dis == 3) { dis = 20; } else { dis = 100; } int windowwid = 920; int windowhig = windowwid * 0.618; initgraph(windowwid, windowhig); setbkcolor(WHITE); cleardevice(); // 加载图片 loadimage(&img, _T("E:\\c++学习\\封装\\对象特性\\tanker\\tanker\\feiji.jpg")); for (int k = 0;; k++) { if (k % dis == 0) { startup(); drawtank(); enemyfire(); } drawplayer(); playermove(); playerfire(); } closegraph(); return 0; }
总结
进行二次开发是一个很好的学习和提升编程能力的方式。
-
熟悉现有代码结构:在开始二次开发之前,首先要仔细阅读和理解现有软件的代码结构、功能和逻辑。这样可以帮助我更好地定位问题和进行修改。
-
确定需求和目标:在进行二次开发之前,我会明确自己的需求和目标,考虑要添加哪些新功能、要优化哪些方面,以便于有针对性地进行修改。
-
小步迭代:我喜欢采用小步迭代的方式进行二次开发,每次只修改少量代码并进行测试,确保每次修改都是有效的,避免一次性修改过多导致问题难以排查。
-
注重代码规范和可维护性:在进行二次开发时,我会注重代码的规范性和可维护性,保持良好的代码结构和注释,遵循设计原则,以便于后续的维护和扩展。
-
不断学习和尝试新技术:在二次开发过程中,我会不断学习和尝试新的技术和工具,以提升自己的技术水平,同时也为软件的改进和优化提供更多可能性。