即使没有按下键,我如何在屏幕上发生某些事情

How do I make something happen on the screen even without a key being pressed?

本文关键字:屏幕      更新时间:2023-10-16

我正在C++用Ncurses库制作Pacman。我可以用我的代码移动 Pacman,但我想移动它,以便 pacman 即使在我没有按任何键时也能继续移动,当我按下另一个方向键时,它会改变方向。现在,吃豆人只在我按下一个键时迈出一步。此外,在吃豆人向那个方向移动之前,我必须按 2 或 3 次键。

if (ch==KEY_LEFT)
{
    int b,row,column;
    getyx(stdscr,row,column);
    int h; 
    do    // do-whileloop to move the pacman left until it hits the wall
    {
        column-=1;
        mvprintw(row,column,">");  //print the ">" symbol
        refresh();
        waitf(0.1);      //this pauses the game for 0.1sec
        attron(COLOR_PAIR(1));      
        mvprintw(row,column,">");
        attroff(COLOR_PAIR(1));
        refresh();
        waitf(0.1);
        mvprintw(row,(b),"O");  //showing the open mouth of pacman
        refresh();
        waitf(0.1);
        attron(COLOR_PAIR(1));a
        mvprintw(row,column,"O");
        attroff(COLOR_PAIR(1));
        h = getch();
    }
    while(h == KEY_LEFT);
}
right = getch();

循环以在 if 条件下向右移动

up = getch();

循环以在 if 条件下向上移动

down = getch();

哎呀,在 if 条件下向下移动。

对此的标准解决方案是有限状态机。角色有六种左右可能的状态:站立、向上移动、向右移动、向下移动、向左移动、死亡。不是直接按键移动字符,而是应该更改字符的状态。

在这样一个小的应用程序中,与其实现一个非常灵活的有限状态机,不如使用一个非常简单的实现,如下所示:

enum PlayerState {
    Standing,
    MovingUp,
    MovingRight,
    MovingDown,
    MovingLeft,
    Dead
};
然后,

在游戏循环中,您可以添加一个非常简单的状态检查,然后对帧采取适当的操作。

switch(state) {
case Standing:
    break;
case MovingUp:
    player.PositionY += 1;
    break;
// ...
}

最后一步是挂钩输入,这取决于检索输入的方法。使用回调,一个例子是:

void KeyDown(Key k) {
    switch(k) {
    case UpArrow:
        if(state != Dead)
            state = MovingUp;
        break;
    case RightArrow:
        if(state != Dead)
            state = MovingRight;
    // ...
    }
}

您可以看到为什么在更大的项目中实现更灵活的有限状态机很重要,但希望此示例为您提供了一个易于理解的想法。

你需要一个等价的kbhit,即非阻塞getch。这真正给出了解决方案,在输入上设置O_NONBLOCK。请参阅此处的示例。一旦你有了这个,只需连续循环,只检查按键命中,没有等待实际按键。

功能getch被阻止,直到按下某个键。如果您不想被阻止,请在getch之前调用_kbhit,并确保输入缓冲区中有一些内容。

编辑:看看ncurses函数nodelaycbreak。它们启用异步输入。

我建议你看看模型-视图-控制器模型,它将帮助您解决此问题以及如果您继续这样编程将遇到的所有其他问题。

编辑:快捷方式

要连续移动你的吃豆人,你需要一个单独的线程来控制它并让它移动。看看pthreads。

如果你只在程序的主运行循环中保留用户输入,你必须按几次键的问题也会消失(这里的问题是当你按下键时处理器必须在 getch() 行上,否则它不会被检测到。

这很容易
每个方向使 4 个功能在函数内部,放入由kbhit激活的其他3个方向函数。

并放置一个 else 语句,如果您不点击按钮,它将继续前进,即 (!kbhit());然后将所有这些放在一个循环中。


如果对所有方向函数执行此操作,您应该能够获得所需的结果。