如何在 ncurses 中的窗口(游戏和暂停窗口)之间切换?

How to juggle between windows (game and pause window) in ncurses?

提问人:rm-star 提问时间:10/11/2023 最后编辑:user16217248rm-star 更新时间:10/11/2023 访问量:46

问:

我正在用 C 语言创建一个游戏。我不是在 stdscr 中玩它,而是在一个名为 .我希望,当用户按“P”时,打开另一个窗口,称为 ,并暂停游戏运行。然后,当用户按“R”进行恢复时,我想“关闭”,并获取我的游戏恢复。特别是,我想看到我的状态与按下“P”之前的状态相同。basewinpausewinbasewinpausewinbasewin

我想我可以通过使用窗口来做到这一点,因为:

  1. 这将使我的代码更干净。
  2. Windows 是内存空间的指针,所以我可以轻松恢复。basewin
  3. 这将是暂停任何游戏的通用方法,退出后不会遇到麻烦。printwpausewin

但我的想法没有奏效。我在一个简化的游戏中尝试了这个:

#include <ncurses.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <stdlib.h> 
    
int main() {
    /* INIT NCURSES */ 
    initscr(); 
    curs_set(0); 
    noecho();
    
    /* INIT PAUSE WIN */
    WINDOW *pausewin = newwin(LINES/3, COLS/3,LINES/3, COLS/3);
    keypad(pausewin,TRUE);
    int cMax_pause, lMax_pause; getmaxyx(pausewin,lMax_pause, cMax_pause);
    box(pausewin,0,0);
    mvwprintw(pausewin,1,cMax_pause/2 -5,"PAUSE WIN");
    mvwprintw(pausewin,lMax_pause/2, cMax_pause/3-4, "[R]ESUME");
    mvwprintw(pausewin,lMax_pause/2, 2*cMax_pause/3-3, "[Q]UIT");
    
    /* INIT BASE WIN */
    WINDOW *basewin = newwin(LINES, COLS/2, 0, COLS/4);
    keypad(basewin,TRUE);
    int lMax, cMax; getmaxyx(basewin, lMax, cMax);
    box(basewin,0,0);
    mvwprintw(basewin,0,2, "[P]AUSE");
    mvwprintw(basewin,1,cMax/2 -4,"BASE WIN");
    
    /* INIT VAR */
    bool loop = true;
    bool pause = false;
    int ch,chp;
    
    /* INIT VARS PLAYER */
    int pline = lMax/2;
    int pcol = cMax/2;
    char pch[2] ; pch[0] = 'M';
    
    /* AFFICHAGE BASE WIN : PRE-LOOP */
    wrefresh(basewin);
    
    /* "GAME" LOOP */
    while(loop){
        
        ch = wgetch(basewin);
        switch(ch){
            case 'p': /* On met le jeu en pause */
            case 'P':
                pause = true;
                break;
            case KEY_LEFT: /* Sinon deplacement */
                pcol -= 1;
                break;
            case KEY_RIGHT:
                pcol += 1;
                break;
            case KEY_UP:
                pline -= 1;
                break;
            case KEY_DOWN:
                pline += 1;
                break;
            default:
                break;
        }
    
    if (pause){
        wrefresh(pausewin);  // HERE IS THE PLACE I HAVE MY PROBLEM
        while(pause){
            chp = wgetch(pausewin);
            switch (chp){
            case 'q':
            case 'Q':
                pause = false;
                loop = false;
                break;
            case 'r':
            case 'R':
                pause = false;
                wrefresh(basewin); // HERE TOO
                break;
            default:
                break;
            }
        }
        
    }
    
    else{
        mvwprintw(basewin,pline,pcol,pch);
    }
    
    wrefresh(basewin);
    }
    
    
    delwin(pausewin);
    delwin(basewin);
    endwin();
    return EXIT_SUCCESS;
}

我对 ncurses 手册的理解相对较好,但我无法做到这一点。 我试图用 来解决这个问题,但它工作一次,然后就再也没有打印过了。 我也尝试使用,但它看起来并不是解决这个问题的好方法。tempwinpausewinoverwrite()

c 窗口 ncurses 暂停 游戏循环

评论

0赞 Oka 10/11/2023
顺便说一句,in 仍然是一个未初始化的不确定值。如果此值恰好不是零字节,则在将此数组用作字符串时,将调用 Undefined Behaviour(例如,使用 )。首选创建字符串。char pch[2] ; pch[0] = 'M';pch[1]mvwprintwchar pch[] = "M";

答:

1赞 Oka 10/11/2023 #1

一个非常简单的方法是调用 touchwin 来指示整个窗口应该重新绘制到屏幕上。

(请注意,wgetch(pausewin) 表示 wrefresh(pausewin) 当窗口被修改时 [在本例中由 touchwin 标记],否则必须调用 wrefresh 才能实际生成输出。wrefresh(basewin) 在主循环的底部调用,而不考虑暂停。)

if (pause) {
    touchwin(pausewin);

    while (pause) {
        chp = wgetch(pausewin);

        switch (chp) {
            case 'q':
            case 'Q':
                pause = false;
                loop = false;
                break;
            case 'r':
            case 'R':
                pause = false;
                touchwin(basewin);
                break;
            default:
                break;
        }
    }
}