控制台游戏需用非阻塞输入(如 _getch() 或 termios)、及时刷新输出(std::flush)、精准光标定位(ansi 或 windows api)、局部重绘、高精度帧率控制(steady_clock)及结构化状态管理。

用 std::cin 和 std::cout 做输入输出,但别卡在阻塞等待上
控制台游戏最基础的交互就是读方向、按空格跳、显示血条——但新手常卡在“按了键没反应”或“输出乱成一团”。根本原因是 std::cin 默认行缓冲,且会因换行符残留导致连续读取失败。
- 每次读完用
std::cin.ignore()清掉缓冲区残留(尤其混用std::cin >>和std::getline()时) - 需要即时响应按键(比如按 A 立刻左移),就不能依赖回车确认:Windows 用
_getch()(<conio.h></conio.h>),Linux/macOS 得自己设终端为非缓冲模式(termios+tcsetattr) -
std::cout输出后加std::flush或std::endl,否则可能延迟显示(尤其重绘场景时)
清屏和光标定位不能靠 system("cls") 或 system("clear")
调用系统命令清屏看着简单,实际埋雷:跨平台失效、进程开销大、在 IDE 内置终端里可能直接不工作(比如 VS Code 的集成终端)。更麻烦的是,它清完就重绘,没法做局部刷新——血条变短你不想重画整个地图吧?
- Windows 下用
SetConsoleCursorPosition+FillConsoleOutputCharacter(<windows.h></windows.h>),精准控制光标和区域填充 - Linux/macOS 用 ANSI 转义序列,比如
"\033[2J\033[H"清屏并归位,"\033[" + std::to_string(y) + ";" + std::to_string(x) + "H"定位光标 - 别在循环里频繁清全屏:只重绘变化区域(比如角色坐标变了,就只重画旧位置和新位置)
游戏主循环里别用 std::this_thread::sleep_for 控制帧率
想让蛇每 100ms 移动一次,于是写个 sleep_for(100ms) ——结果发现:按键响应延迟、动画卡顿、不同机器帧率飘忽。因为 sleep 只保证“至少睡这么久”,实际调度由 OS 决定,误差常达 10–15ms;而且它把整个线程挂起,无法处理输入。
- 用高精度计时器(
std::chrono::steady_clock)记录上一帧时间,每帧计算已过时长,只在真正需要等待时才 sleep - 输入检测必须放在主循环顶部,且用非阻塞方式(如
_kbhit()或轮询poll()+stdin) - 帧率目标设为固定值(如 60 FPS),但允许单帧超时:宁可跳帧,也不要卡住输入
结构体存游戏状态比全局变量安全得多
把玩家 x、y、hp、敌人列表全扔全局变量里,初期写着快,到加技能系统时就会发现:哪次 hp-- 没判零?哪个函数悄悄改了 player.x 却没更新视野?调试时根本分不清数据是谁改的。
立即学习“C++免费学习笔记(深入)”;
- 定义
struct GameState,把所有运行时数据(玩家、怪物、地图、输入状态)全包进去 - 主循环只传引用:
update(gameState, deltaTime)、render(gameState),函数职责清晰,也方便未来加多存档 - 避免裸指针管理资源:怪物死亡就从
std::vector<enemy></enemy>里erase,别留new Enemy出来的野指针
最难的不是画字符或算碰撞,是让输入、渲染、逻辑三者时间轴对齐——光标定位错 1 行,血条就叠在敌人身上;输入检测慢半拍,连招就断。这些细节没有银弹,只能靠 std::chrono 打点、用 gdb 看循环耗时、在关键路径加日志。











