Linux下C语言+ncurses开发Chrome恐龙游戏:实现无阻塞键盘监听
解决ncurses下恐龙游戏的非阻塞输入与游戏循环问题
要实现游戏世界持续运行同时监听键盘输入,核心是把ncurses设置为非阻塞输入模式,结合固定帧率的主循环来处理逻辑。以下是具体实现步骤:
1. 配置ncurses的非阻塞输入
在初始化ncurses时,添加以下关键设置,替代默认的阻塞式输入:
initscr(); // 初始化ncurses环境 cbreak(); // 禁用行缓冲,直接响应单个按键输入 noecho(); // 不回显输入的字符到屏幕 nodelay(stdscr, TRUE); // 将标准窗口设为非阻塞模式,getch()无输入时立即返回ERR keypad(stdscr, TRUE); // 支持识别方向键等特殊按键
其中nodelay(stdscr, TRUE)是核心:它让getch()不再阻塞程序执行,没有按键输入时会立刻返回ERR,确保游戏循环能持续运行。
2. 构建非阻塞的游戏主循环
主循环需要按「输入处理→状态更新→画面渲染→帧率控制」的顺序执行,确保游戏逻辑和输入监听并行:
// 定义恐龙和障碍物的状态结构体 typedef struct { int y; int velocity; int is_jumping; } Dino; typedef struct { int x; int y; int speed; } Obstacle; #define JUMP_FORCE 5 #define GRAVITY 1 #define OBSTACLE_SPEED 2 int main() { // 初始化ncurses initscr(); cbreak(); noecho(); nodelay(stdscr, TRUE); keypad(stdscr, TRUE); // 初始化游戏对象状态 Dino dino = {10, 0, FALSE}; Obstacle obstacle = {COLS, 10, OBSTACLE_SPEED}; while (1) { // 1. 处理键盘输入 int ch = getch(); if (ch != ERR) { // 仅当有输入时处理 if (ch == KEY_UP || ch == ' ') { // 空格或上方向键触发跳跃 if (!dino.is_jumping) { dino.velocity = -JUMP_FORCE; dino.is_jumping = TRUE; } } else if (ch == 'q') { // 按q键退出游戏 break; } } // 2. 更新游戏状态 // 模拟恐龙跳跃与重力落地 if (dino.is_jumping) { dino.y += dino.velocity; dino.velocity += GRAVITY; // 落地检测,重置跳跃状态 if (dino.y >= 10) { dino.y = 10; dino.is_jumping = FALSE; dino.velocity = 0; } } // 移动障碍物,出界后重置位置 obstacle.x -= obstacle.speed; if (obstacle.x < 0) { obstacle.x = COLS; } // 简单碰撞检测 if (dino.y == obstacle.y && obstacle.x <= 5 && obstacle.x >= 0) { mvprintw(LINES/2, COLS/2 - 5, "Game Over!"); refresh(); usleep(2000000); break; } // 3. 渲染游戏画面 clear(); mvprintw(dino.y, 0, "X"); // 绘制恐龙 mvprintw(obstacle.y, obstacle.x, "#"); // 绘制障碍物 refresh(); // 4. 控制帧率(约60帧/秒,每帧间隔16ms) usleep(16667); } // 清理ncurses资源 endwin(); return 0; }
关键注意事项
- 忽略
getch()返回的ERR:没有按键输入时,getch()会返回ERR,此时直接跳过输入处理逻辑即可。 - 强制帧率控制:必须用
usleep()或nanosleep()限制循环速度,否则游戏会因CPU运行过快导致逻辑和画面异常。 - 跳跃状态锁:添加
is_jumping标志,避免玩家连续触发跳跃导致恐龙异常升空。
内容的提问来源于stack exchange,提问作者Andrej Rišian
相关产品推荐
相关产品推荐

