Jeremy
Jeremy

Reputation: 201

ncurses clear() causes flickering

I'm using ncurses for a typing game I'm making. Letters fall down the screen and you must type them before they reach the bottom. It's working great, save one problem. Clearing the window (with clear()) makes the output flicker. I put clear() at the very beginning of the loop and wrefresh() at the very end. Shouldn't it be waiting 'til wrefresh to show anything, thus not flashing?

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <curses.h>
#include <fstream>

using namespace std;

int main(){

  initscr();
  cbreak();
  noecho();
  keypad(stdscr, TRUE);
  nodelay(stdscr, TRUE);

  srand(time(NULL));

  //input character integer (ASCII)
  int ch = 1;
  //int to store the last time the character positions were updated
  int lastupdate = time(NULL);

  //x,y,char arrays for falling characters and initialization
  int chars[10], x[10], y[10];
  for(int i = 0; i < 10; i++){
    chars[i] = rand()%25 + 97;
    x[i] = rand()%30;
    y[i] = 0;
    //y[i] = -(rand()%4);
  }

  while (true){
    clear();
    ch = wgetch(stdscr);

    for (int i = 0; i < 10; i++){
      mvwdelch(stdscr,y[i]-1,x[i]);//delete char's prev. position
      mvwaddch(stdscr, y[i], x[i], chars[i]);//add char's current position
      if (ch == chars[i]){
        mvwdelch(stdscr, y[i], x[i]);
        chars[i] = rand()%25 + 97;
        x[i] = rand()%30;
        y[i] = 0;
      }
    }

    if(time(0) >= (lastupdate + 1)){
      for (int i = 0; i < 10; i++){
        y[i]++;
      }
      lastupdate = time(NULL);
    }

    wmove(stdscr, 20, 0);
    printw("your score is NULL. press ESC to exit");

    scrollok(stdscr, TRUE);
    wrefresh(stdscr);
  }
  endwin();
  return 0;
}

edit: added code

edit2: removed some irrelevant debug code

Upvotes: 6

Views: 7124

Answers (3)

Geek Wisdom
Geek Wisdom

Reputation: 336

I suggest to Just use erase() instead of clear() clear also calls clearok() automatically.

Upvotes: 16

Thomas Dickey
Thomas Dickey

Reputation: 54515

The clear manual page is the place to start:

The clear and wclear routines are like erase and werase, but they also call clearok, so that the screen is cleared completely on the next call to wrefresh for that window and repainted from scratch.

The wgetch call does that wrefresh, which causes the repainting:

If the window is not a pad, and it has been moved or modified since the last call to wrefresh, wrefresh will be called before another character is read.

The description of wrefresh is not nearly so succinct, but "repainting from scratch" will cause flickering since there is a moment when the screen is empty, followed by it being non-empty. Those alternate rapidly due to this call:

nodelay(stdscr, TRUE);

Upvotes: 7

William McBrine
William McBrine

Reputation: 2256

The wgetch() just after the clear() does an implicit wrefresh(). From the wgetch() man page:

If the window is not a pad, and it has been moved or modified
since the last call to wrefresh, wrefresh will be called before
another character is read.

Upvotes: 4

Related Questions