简介
一个基于 ncurses 的简单终端小游戏,包含玩家移动与射击(子弹上移)等核心机制。项目采用模块化设计:Gui 负责渲染与输入,Game 负责游戏状态与主循环,Player 和 Bullet 为游戏实体。
我们将会推出系列文章以实现最终的坦克大战小游戏。本篇为第一节。

运行环境与构建
- 系统:macOS 或 Linux(需支持 ncurses)
- 依赖:
g++、make、ncurses - 构建:
make
- 运行:
./mygame
- 清理:
make clean
提示:按 q 退出程序(也可使用 Ctrl+C 强制结束)。
控制方式
- 方向键:
←、→水平移动;↑、↓垂直移动(持续速度模型) - 空格键:发射子弹(
^符号向上移动) q:退出游戏
边界约束:横向列范围为 [4, 66];纵向行范围约为 [1, 20]。玩家以 M 字符显示。
目录结构
Bullet.C
Bullet.h
Game.C
Game.h
Gui.C
Gui.h
Player.C
Player.h
main.C
makefile
output/
模块设计与实现细节
Gui(终端图形 / 输入封装)
文件:Gui.h, Gui.C
- 初始化与模式设置:
initscr(),noecho(),cbreak(),keypad(win, true),nodelay(win, true)。- 关闭光标
curs_set(0),非阻塞输入(游戏循环无需卡顿等待按键)。
- 边框绘制:
- 在列
4与66画竖线作为左右边界,高度 20 行。 clear()会先擦除窗口再重画边界,确保每帧干净刷新。
- 在列
- 输入与绘制:
get()使用wgetch(win)读取按键;flushinp()清空输入缓存。paintat(row, col, ch)在指定位置绘制字符并立即wrefresh(win)。
- 资源收尾:
~Gui()与end()最终调用endwin()恢复终端状态。
Game(游戏状态 / 主循环调度)
文件:Game.h, Game.C
- 成员:
Gui gui:渲染与输入。Player* pl:玩家对象指针。std::list<Bullet*> bullets:子弹容器。
- 生命周期:
- 构造时
gui.init()并创建玩家:pl = new Player(this)。 - 析构时调用
gui.end()(终止 ncurses)。
- 构造时
- 重要方法:
addBullet(r, c):在位置(r, c)生成子弹并加入bullets。update()(每帧):gui.clear()清屏并重画边界;- 读取输入
int c = gui.get(); pl->update(c)更新玩家(处理输入、移动、发射、绘制);- 遍历
bullets调用update(),并对“越界”子弹执行删除与erase。
注意:当前
update()在erase后仍做一次bi++,可能导致跳过元素(详见“已知问题”)。
Player(玩家实体)
文件:Player.h, Player.C
- 状态:
- 位置:
size_t row,size_t col,初始为(18, 25)。 - 速度 / 方向:
int direction(水平速度,初始 0)、int getrow(垂直速度,未显式初始化,详见“已知问题”)。 Game* game:回调到Game用于发射子弹与绘制。
- 位置:
- 输入与运动模型(持续速度):
KEY_LEFT/KEY_RIGHT:将direction递减 / 递增(按一次改变一次速度)KEY_UP/KEY_DOWN:将getrow递减 / 递增(按一次改变一次速度)space:设置发射标志,调用game->addBullet(row, col)生成子弹。
- 移动与边界:
- 每帧
col += direction; row += getrow;。 - 触碰左右边界时夹紧并将
direction = 0;当row > 20时夹紧并将getrow = 0。 - 绘制玩家:
game->paintat(row, col, 'M')。
- 每帧
Bullet(子弹实体)
文件:Bullet.h, Bullet.C
- 状态:
row,col与Game*。 - 行为:
update():若row > 1则row--上移一行,并在当前位置绘制'^'。out():row <= 0视为越界(由Game::update()删除)。
main(时间步进驱动)
文件:main.C
- 使用
gettimeofday获取毫秒级时间,设定固定步长约 50ms(≈20 FPS)。 - 主循环:
- 控制时间步进(若未到 50ms 就
usleep(26)小休); - 调用
game.update()进行一帧更新; - 更新“上一帧时间戳”。
- 控制时间步进(若未到 50ms 就
makefile(构建脚本)
文件:makefile
- 编译器与库:
g++,-lncurses链接 ncurses。 - 目标:
mygame,依赖main.o Gui.o Game.o Player.o Bullet.o。 - 常用命令:
make、make clean。
游戏循环与帧率
- 固定时间步长(每帧 50ms)保证不同机器上表现一致。
Gui采用非阻塞输入,避免在无按键时卡住主循环。- 每帧顺序:清屏 / 重画边界 → 读取输入 → 更新玩家 → 更新子弹 → 绘制刷新。
内存与资源管理
Game在构造中new Player,在运行时通过addBulletnew子弹。- 子弹在
out()为true时由Game::update()delete并erase。 Gui析构与Game析构中调用endwin(),确保终端恢复。
扩展方向
- 敌人实体与碰撞检测、得分系统、生命 / 血量。
- 粒子 / 尾迹效果、不同子弹类型与射速。
- 更丰富的 UI:帧率 / 得分显示、开始 / 暂停 / 结束界面。
- 配置化边界与地图,或多关卡设计。
我们将在下一节讲解实现更多功能
快速开始
# 构建
make
# 运行
./mygame
# 清理
make clean
发生构建问题时,请确认已安装 Xcode Command Line Tools(macOS)或系统提供的
ncurses开发包(Linux)。
源码
正文完


