【问题标题】:How do I reduce input lag in an NCurses C Application如何减少 NCurses C 应用程序中的输入延迟
【发布时间】:2016-07-12 23:17:32
【问题描述】:

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

更多详情: 当我按“w”、“a”、“s”、“d”(我分配的输入键)时,对象会移动,但是在释放键后它会继续移动很长一段时间。源代码在下面,但是为了缩短问题,已经剪掉了一小部分代码,但是如果下面的源代码无法编译,我会将所有代码都放在 github 上。 https://github.com/TreeStain/DodgeLinuxGame.git 谢谢你的时间。 -特里斯坦

道奇.c:

#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;
 }

render.h:

void render(object obj[], int objectNum);

void render(object obj[], int objectNum)            //Takes array of objects and prints them to screen
 {
    int x, y, i, scrWidth, scrHeight;
    getmaxyx(stdscr, scrHeight, scrWidth);          //Get terminal height and width

    for (y = 0; y < scrHeight; y++)
    {
        for (x = 0; x < scrWidth; x++)
        {
            mvprintw(y, x, " ");
        }
    }

    for (i = 0; i < objectNum; i++)
    {
        int xprint = 0, yprint = 0;
        for (yprint = obj[i].y; yprint < obj[i].y + (obj[i].h * ASPECT_RATIO_Y); yprint++)
        {
            for (xprint = obj[i].x; xprint < obj[i].x + (obj[i].w * ASPECT_RATIO_X); xprint++)
                mvprintw(yprint, xprint, "%c", obj[i].sprite);
        }
    }
    refresh();
}

object.h:

typedef struct
{
    int x, y, w, h, ySpeed, xSpeed;
    char sprite;
}object;

附:请随意批评我的方法和代码,因为我是编程新手,可以接受我能得到的所有批评。

【问题讨论】:

标签: c loops input delay ncurses


【解决方案1】:

我相信原因是因为 getch() 一次只会释放一个输入字符(即使输入流中有很多排队)所以如果它们排队的速度比你从流中“删除”它们的速度更快,即使您释放密钥,循环仍将继续,直到队列清空。此外,您还需要 (1000 / FRAMES_PER_SECOND) 以毫秒为单位获得所需的延迟时间(这会产生每秒 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 并继续前进。然后循环应该休眠约 17 毫秒并重复。这些行应该强制循环每约 17 毫秒只“计数”一次按键,并且不会比这更频繁。

见:http://linux.die.net/man/3/getch

【讨论】:

  • 感谢这解决了我的问题,让我更好地了解了 C 和 NCurses 的工作原理。
  • 你也可以使用内置的 flushinp()
【解决方案2】:

Ncurses 不会分别检测按键和按键释放。按住键时不能移动对象,松开后立即停止。

您观察到的现象是由两个因素共同导致的:自动重复键盘和缓冲键盘驱动程序。也就是说,用户持有一个键,这会产生大量的键事件,它们被驱动程序缓冲,并在应用程序请求按键时提供给您的应用程序。

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

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

您需要使用实时时钟每次计算 timeToRefresh。

【讨论】:

  • 谢谢你,这对我的理解很有帮助。
猜你喜欢
  • 2018-10-08
  • 1970-01-01
  • 2012-08-10
  • 1970-01-01
  • 2017-10-04
  • 2015-01-23
  • 1970-01-01
  • 2018-12-06
相关资源
最近更新 更多