C++ 按esc退出程序 总结

这篇博客总结了如何在C++程序中通过按下ESC键退出程序的三种实现方式,包括使用<int>和<char>类型的变量,以及对ESC键ASCII码的理解。尽管这些方法在VS2005上调试成功,但由于_cgetch()会导致输入数据时的第一个字符无法显示,作者最终决定放弃使用这些方法。

         这几天老师叫我们用C++编个学生信息管理的软件,就当是作业。我们小组编完后,想在里面添加个功能,就是按esc退出程序或者回到前一个界面。我在网上找了一番,百度上关于这方面的问题挺多的,但是发现有些代码在我上面不能运行。我又自己试了下,发现了几种可以运行的情况:

 

1.  #include <iostream>
     #include <conio.h>
     #include <stdlib.h>
     using namespace std;


     void main()
     {
          int c;
          cout<<"aaa";        //这一段只是在屏幕上显示“aaa”,没有什么实际含义

          c=_getch();
          if(c==27) exit(0);

          else 
          { cout<<"zzz";
             _getch();
          }

     }                               //此段代码在VS2005上调试成功

     这里定义了一个整型c,则 通过c=_getch()c返回的值是一个整数。是由于escASC码值为27,这里你按了esc键,c值就为27,然后if判断下,符合条件就退出。

      后面的else语句其实没有什么用,只不过如果没有else语句的话,你无论按什么键程序都会退出来,因为if后面没有其他语句了。else语句只是让你看到你按了esc其实是有用的。

 

2.  我然后把c的类型定义为char,同时c==27,即:

     #include <iostream>
     #include <conio.h>
     #include <stdlib.h>
     using namespace std;
     void main()
     {
         char c;
         cout<<"aaa";
         c=_getch();
         if(c==27) exit(0);

         else 
         { cout<<"zzzz";
            _getch();
          }         

     }                              //此段代码在VS2005上调试成功

      这段代码生成后还是可以运行的,然后我就想看看char c在按了esc后其值到底是多少。于是有了下面的代码。。。

 

3.  #include <iostream>

     #include <conio.h>
     #include <stdlib.h>
     using namespace std;
     void main()
     {
          char c;
          cout<<"aaa";
          c=_getch();
          if(c=='') exit(0);  // 这里''是一个特殊符号      

          else
          { cout<<"zzzz";
            _getch();
          }                   
     

     }                               //此段代码在VS2005上调试成功

      我重新建了个项目,把上面的代码拷过去后,是可以运行的。

      这里的变量c定义为字符型,这下大家可能会有点不解,为什么c==''呢?等我慢慢道来。我在if那里设置了一个断点,然后看c的值,如下图:

 断点调试中c的值

 

 其中c的值显示是27'□',我在搜狗输入法里找了下,特殊符号的P键就是'□' 。但是你点击27'□'时,又变成了''。如果你把“''”复制到“c==27”那里,把27覆盖掉,你会发现那里两个单引号之间空荡荡的,像是加了个空格。不要急,其实那只是看上去像空格而已,其实里面是有东西的。如果你把那空荡荡的东西复制到记事本里,他会变成这样:

插入记事本的样子 

我又把它复制到Notepad++(一款文本编辑软件)里面去,它才露出了一丝本来面目:

Notepad++中显示样子 

看到了么?esc。。原来如此。。

       以上就是我总结出来的方法,但遗憾的是我们并不准备在我们的程序中使用,因为他们都有个c=_getch();这导致输入数据的时候,你若是不想退出,那你输入的第一个字符时无法显示的。。这让我极其不爽,于是,我放弃了。。

 

 

好的!我们将继续改进这个光线投射程序,加入以下两个功能: --- ## ✅ 新增功能: 1. **按 `Esc` 键退出程序**:使用 `WM_KEYDOWN` 消息检测 `VK_ESCAPE`。 2. **取消鱼眼效果**:在光线投射中使用**垂直视角偏移**,并优化投影逻辑,使画面更真实。 --- ## ✅ 主要改动说明: - 在消息处理中加入对 `Esc` 的检测,退出主循环。 - 在 `castRays()` 中优化投影方式: - 使用垂直视角(FOV)计算正确投影高度。 - 使用 `cos(rayAngle - playerDir)` 进行精确距离校正。 - 去除简单的线段绘制,改为矩形绘制,增强真实感。 --- ## ✅ 改进后的完整代码: ```cpp #include <graphics.h> #include <conio.h> #include <math.h> #include <windows.h> #include <stdio.h> // 地图尺寸 const int MAP_WIDTH = 10; const int MAP_HEIGHT = 10; // 屏幕分辨率 const int SCR_WIDTH = 1024; const int SCR_HEIGHT = 768; // 光线数量 const int NUM_RAYS = SCR_WIDTH; // 墙高缩放因子 const double WALL_HEIGHT = 1.0; // 视角旋转速度和移动速度 const double ROT_SPEED = 0.05; const double MOVE_SPEED = 0.05; // 视角 FOV(水平视野角度) const double FOV = M_PI / 3.0; // 定义 M_PI #ifndef M_PI #define M_PI 3.14159265358979323846 #endif // 地图定义(true 表示墙) bool map[MAP_WIDTH][MAP_HEIGHT] = { {1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,1,0,0,0,1}, {1,0,0,0,0,1,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,1,1,1,1,1,1,1,1,1} }; // 玩家位置 double playerX = 1.5; double playerY = 1.5; double playerDir = 0; // 光线投射函数 void castRays() { for (int x = 0; x < NUM_RAYS; x++) { double rayAngle = (playerDir - FOV / 2 + (x * FOV / NUM_RAYS)); double distToWall = 0; bool hitWall = false; double rayX = cos(rayAngle); double rayY = sin(rayAngle); while (!hitWall && distToWall < 20) { distToWall += 0.05; int testX = (int)(playerX + rayX * distToWall); int testY = (int)(playerY + rayY * distToWall); if (testX < 0 || testX >= MAP_WIDTH || testY < 0 || testY >= MAP_HEIGHT) { hitWall = true; distToWall = 20; } else if (map[testX][testY]) { hitWall = true; distToWall *= cos(rayAngle - playerDir); // 校正鱼眼效果 } } // 真实投影高度(垂直视角) int wallHeight = (int)(WALL_HEIGHT / distToWall * SCR_HEIGHT); // 计算顶部和底部位置(居中显示) int startY = (SCR_HEIGHT - wallHeight) / 2; int endY = (SCR_HEIGHT + wallHeight) / 2; COLORREF color = RGB(255 - (int)(distToWall * 10), 255 - (int)(distToWall * 10), 255 - (int)(distToWall * 10)); setfillcolor(color); solidrectangle(x, startY, x + 1, endY); } } // 玩家移动函数 void movePlayer(bool keys[256]) { double moveX = 0, moveY = 0; if (keys['W']) { moveX = cos(playerDir) * MOVE_SPEED; moveY = sin(playerDir) * MOVE_SPEED; } if (keys['S']) { moveX = -cos(playerDir) * MOVE_SPEED; moveY = -sin(playerDir) * MOVE_SPEED; } if (keys['A']) { moveX = cos(playerDir - M_PI / 2) * MOVE_SPEED; moveY = sin(playerDir - M_PI / 2) * MOVE_SPEED; } if (keys['D']) { moveX = cos(playerDir + M_PI / 2) * MOVE_SPEED; moveY = sin(playerDir + M_PI / 2) * MOVE_SPEED; } int testX = (int)(playerX + moveX); int testY = (int)(playerY + moveY); if (!map[testX][testY]) { playerX += moveX; playerY += moveY; } } int main() { initgraph(SCR_WIDTH, SCR_HEIGHT); // 初始化窗口 POINT oldMousePos; GetCursorPos(&oldMousePos); bool keys[256] = { false }; bool running = true; ExMessage msg; while (running) { // 处理消息队列 while (peekmessage(&msg)) { if (msg.message == WM_KEYDOWN) { keys[msg.vkcode] = true; if (msg.vkcode == VK_ESCAPE) { running = false; // 按下 Esc 退出 } } else if (msg.message == WM_KEYUP) { keys[msg.vkcode] = false; } } // 鼠标控制视角 POINT currentMousePos; GetCursorPos(&currentMousePos); int deltaX = currentMousePos.x - oldMousePos.x; playerDir += deltaX * ROT_SPEED / 10; SetCursorPos(oldMousePos.x, oldMousePos.y); // 锁定鼠标位置 // 移动玩家 movePlayer(keys); // 双缓冲绘图 BeginBatchDraw(); cleardevice(); castRays(); EndBatchDraw(); Sleep(10); } closegraph(); return 0; } ``` --- ## ✅ 代码解释: ### ✅ 1. `Esc` 退出功能: - 使用 `WM_KEYDOWN` 检测按键消息。 - 如果 `msg.vkcode == VK_ESCAPE`,设置 `running = false` 退出主循环。 ### ✅ 2. 取消鱼眼效果: - 光线角度使用 `playerDir - FOV / 2 + (x * FOV / NUM_RAYS)`,实现完整 FOV。 - 使用 `distToWall *= cos(rayAngle - playerDir)` 对距离进行精确校正。 - 使用 `solidrectangle()` 绘制墙块,增强真实感。 --- ## ✅ 编译运行说明: - 使用 Dev-C++ 创建一个 C++ 项目。 - 确保已安装 EasyX 库(推荐使用 20201210 或 20220900 版本)。 - 将上述代码粘贴进主源文件。 - 编译并运行程序。 - 按 `Esc` 键可退出。 --- ## ✅ 功能总结: | 功能 | 实现方式 | |------------------|----------| | 按 Esc 退出 | 使用 `WM_KEYDOWN` 检测 `VK_ESCAPE` | | 消除鱼眼效果 | 使用 `cos(rayAngle - playerDir)` 校正距离 | | 更真实的投影 | 使用 `solidrectangle()` 绘制墙块 | | 双缓冲绘图 | 使用 `BeginBatchDraw()` 和 `EndBatchDraw()` | --- ##
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值