Проблемы с проклятиями C++

Недавно я начал использовать PDcurses для Windows. Я написал простую программу, которая создает окно и перемещает символ в соответствии с вводом пользователя, вверх для «w», вниз для «s» и так далее.

Происходят 2 странные вещи:

  1. Всякий раз, когда я перемещаю персонажа вниз, удерживая s, он исчезает, не позволяя пользователю видеть движение.
  2. Всякий раз, когда я перемещаю персонажа в сторону, он оставляет след (вроде) синего цвета, если он идет вправо, и красного, если он идет влево.

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

Вот код С++. Он рисует в начале цикла, ищет входные данные в середине и обновляет экран в конце. Я установил getch(), чтобы не прерывать выполнение с помощью nodelay().

initialize();
WINDOW* stage= createstage();
int ywindow,xwindow,heightwindow,widthwindow;

getbegyx(stage,ywindow,xwindow);
getmaxyx(stage,heightwindow,widthwindow);
heightwindow--;
widthwindow--;
int x = xwindow+1, y = ywindow+1;
char c = '@';


while(TRUE){

    box(stage,0,0);
    wmove(stage,y,x);
    wprintw(stage,"%c",'@');

    c=getch();
    if(c=='w' && y-1>ywindow){
        y--;
    }
    if (c=='s' && y+1<heightwindow){
        y++;
    }
    if(c=='d' && x+1<widthwindow){
        x++;
    }
    if(c=='a' && x-1>xwindow){
        x--;
    }
    wrefresh(stage);
    Sleep(16);
    wclear(stage);
}

person Fiabio    schedule 07.02.2021    source источник
comment
Это может быть артефакт синхронизации и обновления экрана. Что произойдет, если вы измените задержку в вызове Sleep? Или рисовать персонажа перед рисованием коробки? Или изменить порядок, чтобы вы получили персонажа, перерисовали экран, обновились, а затем заснули?   -  person 1201ProgramAlarm    schedule 07.02.2021
comment
@ 1201ProgramAlarm Спасибо за ответ. Установка времени сна на значение >60 решает первую проблему, но, конечно, у персонажа будет больше задержки при перемещении, и следы также останутся. Использование всех других предложений ничего не исправит.   -  person Fiabio    schedule 07.02.2021
comment
1. Это не полный пример программы. 2. Я настоятельно рекомендую использовать napms() (встроено в curses, разрешает фоновую обработку) вместо Sleep() (зависит от Windows, останавливает поток). 3. Рассмотрите возможность стирания и перерисовки только символа, а не всего окна. 4. Тем не менее, следы звучат как артефакт терминала, а не то, что вы сможете исправить на уровне проклятий.   -  person William McBrine    schedule 08.02.2021


Ответы (1)


Обновление: Прежде всего прикрепляю полный исходник программы:

#include "curses.h"
#include <windows.h>

void disableselection(){
  HANDLE hInput;
  DWORD prev_mode;
  hInput = GetStdHandle(STD_INPUT_HANDLE);
  GetConsoleMode(hInput, &prev_mode);
  SetConsoleMode(hInput, prev_mode & ENABLE_EXTENDED_FLAGS);
}

void disableresizing(){
  HWND consoleWindow = GetConsoleWindow();
  SetWindowLong(consoleWindow, GWL_STYLE, GetWindowLong(consoleWindow, GWL_STYLE) & ~WS_MAXIMIZEBOX & ~WS_SIZEBOX);
}

void initialize(){
  initscr();
  curs_set(0);
  disableselection();
  disableresizing();
  noecho();     
  nodelay(stdscr,TRUE);    
}

WINDOW* createstage(int starty=0, int startx=0, int height=LINES, int width=COLS-COLS*1/5){
  WINDOW* win=newwin(height-starty,width-startx,starty,startx);
  refresh();
  return win;
}

void end(WINDOW* stage){
  clear();
  refresh();
  nodelay(stdscr,FALSE);
  printw("press something to exit");
  getch();
  endwin();
}

int main(){
  initialize();
  WINDOW* stage= createstage();
  int ywindow,xwindow,heightwindow,widthwindow;
  getbegyx(stage,ywindow,xwindow);
  getmaxyx(stage,heightwindow,widthwindow);
  heightwindow--;
  widthwindow--;
  int x = xwindow+1, y = ywindow+1;
  char c = '@';
  while(TRUE){
    box(stage,0,0);
    wmove(stage,y,x);
    waddch(stage,'@');
    wrefresh(stage);
    c=wgetch(stage);
    if(c=='w' && y-1>ywindow){
      y--;
    }
    if (c=='s' && y+1<heightwindow){
      y++;
    }
    if(c=='d' && x+1<widthwindow){
      x++;
    }
    if(c=='a' && x-1>xwindow){
      x--;
    }
    napms(16);
    werase(stage);
    wrefresh(stage);
 }
 end(stage);
}

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

Коробка (именно верхняя сторона) мерцает всякий раз, когда я двигаюсь. Это происходит, даже если я помещаю вызов box(stage,0,0); в начало цикла.

Я попытался нарисовать блок с помощью stdscr, а также создать подокно для использования в качестве основной сцены и нарисовать блок в родительском окне. Еще одна вещь, которую я пробовал, - это удалить функции Windows API, думая, что они конфликтуют. Ни одна из этих идей не сработала.

person Fiabio    schedule 08.02.2021