Как напечатать две вещи одновременно с ncurses

Я делаю игру в ncurses, похожую на космических захватчиков.

До сих пор я получил движение и сбил, но я столкнулся с проблемой.

Когда игрок запускает лазер, я использую услужливый вызов, чтобы задержать движение лазера по экрану, чтобы он не просто показывался с одного конца экрана на другой.

Проблема с использованием usleep для задержки лазера означает, что игрок не может двигаться, пока лазер перемещается по экрану, пока петля не выйдет.

У меня вопрос, есть ли другой способ печати лазера, движущегося по экрану, в то же время перемещая плеер / курсор с помощью пользовательского ввода?

Когда пользователь нажимает клавишу "F", следующий код перемещает линию (лазер) по экрану. Однако пользователь не может двигаться дальше, пока лазер не покинет экран:

void combat(int y, int x)
{
    do
    {
        mvprintw(y -1, x, "|");
        refresh();
        y--;
        usleep(50000);
        mvprintw(y , x, " ");   
    }
    while(y>0);
}

3 ответа

Решение

На самом деле я нашел достойное решение своей проблемы, поэтому оставлю это здесь на случай, если у кого-нибудь возникнет аналогичная проблема в будущем.

Когда моя программа входит в боевую функцию, она также входит в режим нодлаев, что делает неблокирующим getch(). Поскольку функция циклически переходит в спящий режим, пользователь может в любое время ввести символ, заставляя корабль двигаться, и, поскольку он не находится в режиме задержки, getch () не блокирует выполнение функции ожидания, если пользователь решает остаться на месте.

Боевая функция, которая выполняется, когда пользователь нажимает "f":

void combat(int y, int x)
{
int input;
int y2 = y;
int x2 = x;
do
{
    mvprintw(y2 -1, x2+1, "|");
    refresh();
    y2--;
    mvprintw(y2 , x2+1, " ");
    usleep(50000);
    nodelay(stdscr, TRUE);
    input = getch();

    switch(input)
    {
        case 'w':
        mvprintw(y, x,"   ");
        y--;
        mvprintw(y, x,"^V^");
        break;

        case 'a':
        mvprintw(y, x+2," ");
        x--;
        mvprintw(y, x,"^V^");
        break;

        case 's':
        mvprintw(y, x,"   ");
        y++;
        mvprintw(y, x,"^V^");
        break;

        case 'd':
        mvprintw(y, x," ");
        x++;
        mvprintw(y, x,"^V^");
        break;

    }

}
while(y2>0);
movement(y,x);

}

Самым простым решением было бы написать вашу программу с циклом, содержащим одну инструкцию сна, например:

frame_timer = 0;
while (1) {
  if (player_is_alive) {
    move_player();
    move_aliens();
    move_laser_bullets();
    check_collisions();
  }
  else {
    draw_explosion();
    if (explosion_finished) break;
  }
  frame_timer++;
  usleep(20000);  /* Refresh at approximately 50fps */
}

Эта проблема не может быть легко решена без внешнего потока. Отключение функции сна путем привязки движения лазера к входу (так что положение обновляется только тогда, когда экран должен обновляться внешним входом) не будет работать, потому что вам нужно, чтобы лазер был независим от всего остального.

Грязный хак может иметь:

  • неблокирующие функции ввода через int nodelay(WINDOW *win, bool bf) так что функция ввода ничего не заблокирует
  • заданная (достаточно высокая) частота обновления, например, 10 FPS (сон 100 мс)
  • обновлять положение лазера только один раз каждые несколько кадров, чтобы он двигался достаточно медленно, но достаточно часто опрашивал входные данные
Другие вопросы по тегам