简易的射击坦克小游戏(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;
}
View Code

 由绿色源点发射激光

 

对于上述问题的细化改进

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;
}
View Code

 

 

 

总结

进行二次开发是一个很好的学习和提升编程能力的方式。

  1. 熟悉现有代码结构:在开始二次开发之前,首先要仔细阅读和理解现有软件的代码结构、功能和逻辑。这样可以帮助我更好地定位问题和进行修改。

  2. 确定需求和目标:在进行二次开发之前,我会明确自己的需求和目标,考虑要添加哪些新功能、要优化哪些方面,以便于有针对性地进行修改。

  3. 小步迭代:我喜欢采用小步迭代的方式进行二次开发,每次只修改少量代码并进行测试,确保每次修改都是有效的,避免一次性修改过多导致问题难以排查。

  4. 注重代码规范和可维护性:在进行二次开发时,我会注重代码的规范性和可维护性,保持良好的代码结构和注释,遵循设计原则,以便于后续的维护和扩展。

  5. 不断学习和尝试新技术:在二次开发过程中,我会不断学习和尝试新的技术和工具,以提升自己的技术水平,同时也为软件的改进和优化提供更多可能性。

 

  

posted @ 2024-03-05 18:33  yzy001  阅读(35)  评论(0编辑  收藏  举报