如何减少NCurses C应用程序中的输入延迟

如何减少NCurses C应用程序中的输入延迟,c,loops,input,delay,ncurses,C,Loops,Input,Delay,Ncurses,当我运行我的应用程序时,我得到了大量的输入延迟 更多详情: 当我按下“w”、“a”、“s”、“d”(我指定的输入键)时,对象会移动,但在释放键后,它会继续移动一段较长的时间。下面是源代码,但是为了缩短问题,删去了代码的一小部分。但是,如果下面的源代码没有编译,我将所有代码都放在github上。 谢谢你抽出时间-特里斯坦 道奇: #define ASPECT_RATIO_X 2 #define ASPECT_RATIO_Y 1 #define FRAMES_PER_SECOND 60 #incl

当我运行我的应用程序时,我得到了大量的输入延迟

更多详情: 当我按下“w”、“a”、“s”、“d”(我指定的输入键)时,对象会移动,但在释放键后,它会继续移动一段较长的时间。下面是源代码,但是为了缩短问题,删去了代码的一小部分。但是,如果下面的源代码没有编译,我将所有代码都放在github上。 谢谢你抽出时间-特里斯坦

道奇:

#define ASPECT_RATIO_X 2
#define ASPECT_RATIO_Y 1
#define FRAMES_PER_SECOND 60

#include <ncurses.h>
#include "object.h"
#include "render.h"

int main()
{
    initscr();
    cbreak();
    noecho();
    nodelay(stdscr, 1);

    object objs[1];

    object colObj; colObj.x = 10; colObj.y = 6;
                   colObj.w = 2;  colObj.h = 2;
                   colObj.sprite = '*';
                   colObj.ySpeed = 1;
                   colObj.xSpeed = 1;

    objs[0] = colObj;

    //halfdelay(1);

    while (1)
    {
        char in = getch();
        if (in == 'w')
            objs[0].y -= objs[0].ySpeed * ASPECT_RATIO_Y;
        if (in == 's')
            objs[0].y += objs[0].ySpeed * ASPECT_RATIO_Y;
        if (in == 'a')
            objs[0].x -= objs[0].xSpeed * ASPECT_RATIO_X;
        if (in == 'd')
            objs[0].x += objs[0].xSpeed * ASPECT_RATIO_X;
        render(objs, 1);
        napms(FRAMES_PER_SECOND);
    }

    getch();

    endwin();
    return 0;
 }

另外,请随意评论我的方法和代码,因为我对编程相当陌生,可以接受所有批评。

我相信原因是getch()一次只释放一个输入字符(即使输入流中有许多字符排队),所以如果它们排队的速度比您从流中“删除”它们的速度快,循环将继续,直到队列清空,即使在您释放密钥之后也是如此。此外,您还需要执行(1000/帧/秒)以获得所需的延迟时间(毫秒)(这将创建每秒60帧)

在你的while循环中试试这个

while (1)
    {
        char in;
        /* We are ready for a new frame. Keep calling getch() until we hear a keypress */
        while( (in = getch()) == ERR) {}

        if (in == 'w')
            objs[0].y -= objs[0].ySpeed * ASPECT_RATIO_Y;
        if (in == 's')
            objs[0].y += objs[0].ySpeed * ASPECT_RATIO_Y;
        if (in == 'a')
            objs[0].x -= objs[0].xSpeed * ASPECT_RATIO_X;
        if (in == 'd')
            objs[0].x += objs[0].xSpeed * ASPECT_RATIO_X;
        render(objs, 1);

        /* Clear out any other characters that have been buffered */
        while(getch() != ERR) {}

        napms(1000 / FRAMES_PER_SECOND);
    }
从循环的顶部:
while((in=getch())==ERR){}
将快速调用getch(),直到检测到按键为止。如果未检测到按键,getch()将返回ERR。
while(getch()!=ERR){}
所做的是继续调用getch(),直到从队列中删除所有缓冲输入字符,然后getch()返回ERR并继续。然后循环应休眠约17ms并重复。这些行应该强制循环每17ms只“计数”一次按键,并且不超过这个频率


请参阅:

Ncurses不会单独检测按键和按键释放。不能在按住键的同时移动对象,也不能在释放对象后立即停止

您观察到的现象是由两个因素组合而成的:自动重复键盘和缓冲键盘驱动程序。也就是说,用户持有一个键,这会生成大量的键事件,驱动程序会缓冲这些事件,并在应用程序要求按键时将其提供给应用程序

驱动程序和键盘自动重复功能都不受应用程序的控制。您唯一希望实现的是,处理关键事件的速度要快于键盘输出的速度。如果要这样做,必须在主循环中去掉
napms
,并在帧重新绘制之间处理按键。有很多方法可以做到这一点,但最简单的方法是使用
timeout
函数

 timeout (timeToRefresh);
 ch = getch();
 if (ch == ERR) refresh();
 else processKey(ch);

您需要使用实时时钟计算每次刷新的时间。

您可能需要评测代码。在这里寻找你可以使用的工具:它可能不是你问题的解决方案。但是我将替换对
mvprintw(y,x,“”)的多重调用。这对我的理解有很大帮助。谢谢,这解决了我的问题,让我更好地理解了C和NCurses的工作原理。你也可以使用内置的flushinp()
while (1)
    {
        char in;
        /* We are ready for a new frame. Keep calling getch() until we hear a keypress */
        while( (in = getch()) == ERR) {}

        if (in == 'w')
            objs[0].y -= objs[0].ySpeed * ASPECT_RATIO_Y;
        if (in == 's')
            objs[0].y += objs[0].ySpeed * ASPECT_RATIO_Y;
        if (in == 'a')
            objs[0].x -= objs[0].xSpeed * ASPECT_RATIO_X;
        if (in == 'd')
            objs[0].x += objs[0].xSpeed * ASPECT_RATIO_X;
        render(objs, 1);

        /* Clear out any other characters that have been buffered */
        while(getch() != ERR) {}

        napms(1000 / FRAMES_PER_SECOND);
    }
 timeout (timeToRefresh);
 ch = getch();
 if (ch == ERR) refresh();
 else processKey(ch);