2016-03-25 26 views
3

我在运行我的应用程序时遇到主要的输入滞后量。如何减少NCurses C应用程序中的输入滞后

更多详细信息: 当我按'w','a','s','d'(我分配的输入键)时,物体会移动,但在键持续一段时间后它会继续移动被释放。源代码在下面,但是代码的小部分已经被剪掉以缩短问题,但是如果下面的源代码不能编译,我将所有的代码放在github上。 https://github.com/TreeStain/DodgeLinuxGame.git谢谢你的时间。 -Tristan

dodge.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; 

P.S.请随时批评我的方法和代码,因为我在编程方面相当新颖,可以采取所有我能得到的批评。

+0

您可能想要分析您的代码。在这里寻找你可以使用的工具:http://softwarerecs.stackexchange.com/questions/9992/linux-c-profiler – Plouff

+0

这可能不是你的问题的解决方案。但是如果可能的话,我会用多次调用“mvprintw(y,x,”“);'”来调用多次调用。 https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html可能会帮助 – Plouff

回答

3

我相信原因是因为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并继续。然后循环应该睡~17ms并重复。这些行应该强制循环每17ms只能“计数”一次按键,并且不会比这更频繁。

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

+0

感谢这解决了我的问题,并让我更好地理解C和NCurses如何工作。 –

+0

不客气! – jrsmolley

+0

你也可以使用内置的flushinp() –

1

的Ncurses不单独检测按键和按键松开。在按住某个按键时不能移动对象,并在释放后立即停止。

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

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

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

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

+0

谢谢你对我的理解有了很大的帮助。 –