В настоящее время пытаюсь решить проблему с мерцанием в очень маленькой игре, которую я делаю в ncurses с C++. Мерцание не вызывает отвращения, но я могу себе представить, что оно гораздо более раздражает, когда одновременно визуализируется/двигается больше объектов. Код ниже. Также есть заголовочный файл, но я не думаю, что он здесь уместен.
#include "game.h"
// only real note is that the sprite char** must be NULL terminated
class Entity {
public:
int x;
int y;
//these are mainly here for bounds checking
int width;
int height;
//position and sprite are needed by outside methods, but nothing else should be
// this needs to be stored as an array of chars* in order to properly render the sprite
// the sprite array also needs to be null terminated
const char** sprite;
Entity(int y, int x, const char** sprite) {
this->y = y;
this->x = x;
this->sprite = sprite;
this->width = getWidth();
this->height = getHeight();
};
int getWidth() {
int w_max = 0, i = 0;
while (this->sprite[i] != NULL) {
int line_width = strlen(sprite[i]);
if (line_width > w_max) {
w_max = width;
}
i++;
}
return w_max;
}
int getHeight() {
int current_height = 0, i = 0;
while (this->sprite[i] != NULL) {
current_height++;
i++;
}
return current_height;
}
};
class Player: public Entity {
public:
Player(int y, int x, const char** sprite) : Entity (y, x, sprite) {}
int move(int proposed_direction) {
int right = 0, down = 0;
switch(proposed_direction) {
case KEY_LEFT:
right--;
break;
case KEY_RIGHT:
right++;
break;
case KEY_UP:
down--;
break;
case KEY_DOWN:
down++;
break;
case 'q':
endwin();
exit(0);
break;
default:
down++;
break;
}
this->y += down;
this->x += right;
return -1;
}
// int check(int proposed_direction) {
// return -1;
//
// }
};
void screenStart() {
initscr();
noecho();
curs_set(FALSE);
//honestly not sure why this is required
nodelay(stdscr, TRUE);
//timeout(-1);
keypad(stdscr, TRUE);
}
void drawEntity(Entity* entity) {
//this is to print out every line of the sprite in order at the right place
for (int i = 0; entity->sprite[i] != NULL; i++) {
// the + i is there because it draws horizontally line by line
mvprintw(entity->y + i, entity->x, entity->sprite[i]);
}
}
int main() {
screenStart();
const char* player_sprite[] = {"XX", "XX", NULL};
Player* player = new Player(15, 15, player_sprite);
int ch;
for (;;) {
erase();
if ((ch = getch()) == ERR) {
drawEntity(player);
}
else {
player->move(ch);
drawEntity(player);
}
wnoutrefresh(stdscr);
doupdate();
napms(16);
}
endwin();
return 0;
};
Я пытался уменьшить размер терминала, лучше рассчитать время ожидания и т. д., но хотел убедиться, что не делаю ничего серьезного, прежде чем что-то делать. Перерисовка только части окна может помочь, но я не знаю, будет ли это хорошо масштабироваться? Я открыт для любых советов по поводу проклятий в целом.
РЕДАКТИРОВАТЬ: Новый код ниже, после изменения порядка перерисовки/очистки/вызовов без мерцания:
for (;;) {
werase(win);
auto startTime = std::chrono::steady_clock::now();
box(win, 0, 0);
player->drawEntity();
int ch = wgetch(win);
if (ch != ERR) {
player->move(ch);
}
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - startTime);
napms(WAIT_TIME - diff.count());
}
Да, это был ответ, который мне дал кто-то другой, и это правильно. Ни один из учебников/других сообщений на SO, который я нашел, на самом деле не показал пример этого, поэтому я буду редактировать то, что у меня есть в настоящее время, в свои вопросы. Спасибо!