2016-03-25 50 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

謝謝你對我的理解有了很大的幫助。 –