fillRect() and fillScreen() too slow and flickers too much

I am trying to make a space invanders game but when I move the sprite accross the screen it flickers too much. Can anyone help?

Here is the code:

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1351.h>

// OLED Display Dimesions (pixels)
#define OLED_WIDTH 128
#define OLED_HEIGHT 128

// OLED Display PINS
#define DIN_PIN 12
#define CLK_PIN 11
#define CS_PIN 10
#define DC_PIN 9
#define RST_PIN 8

// On / Off Button Pin
#define OnOff_TOGGLE_SWITCH_PIN 4

// OLED Colours
#define  BLACK           0x0000
#define BLUE            0x001F
#define RED             0xF800
#define GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

Adafruit_SSD1351 display = Adafruit_SSD1351(OLED_WIDTH, OLED_HEIGHT, CS_PIN, DC_PIN, DIN_PIN, CLK_PIN, RST_PIN);


// OLED Graphics
static const unsigned char PROGMEM InvaderMiddleGfx [] =
{
  B00100000,B10000000,
  B00010001,B00000000,
  B00111111,B10000000,
  B01101110,B11000000,
  B11111111,B11100000,
  B10111111,B10100000,
  B10100000,B10100000,
  B00011011,B00000000
};

int XPos = 0;

void setup()
{
  Serial.begin(9600);
  Serial.println("Serial started on baud: 9600.");

  display.begin();
  display.fillScreen(BLACK);
}

void loop()
{
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.print("Space Invaders");
  display.drawBitmap(XPos, 20, InvaderMiddleGfx, 11 , 8, WHITE);
  display.fillRect(XPos, 20, 11, 8, BLACK);
  XPos += 1;
  if(XPos > 127)
    XPos = 0;
}

I am using Arduino Uno and a 1.5" RGB OLED Module with the Adafruit_ssd1351 library.
Here is the OLED: 1.5inch Rgb Oled Screen Display Module Ssd1351 Driver 128x128 16-bit High Color Display Supports For Raspberry Pi /arduino/stm32 - Led Displays - AliExpress

Start by not setting the colour, positioning the cursor and printing the text in every iteration of loop() as it never changes.

Do you really need to draw and update the XPos on every iteration of loop() ?

No, I dont think so, but I do need something that can clear the screen fast.
I am following this tutorial : Part 1 OLED, plotting graphics and basic movement - XTronical
And he uses the ssd1306 which has the clearDisplay() but ssd1351 doesn't, so I just need another varient of it that can clear the screen in an instant.

The problem is that nothing happens "in an instant" as the more pixels that are involved the more time it takes to change them

Instead of clearing the whole screen consider writing the invader graphic in the background colour to erase it

So make the invader black then white everytime?

like this:

void loop()
{
  display.drawBitmap(XPos, 20, InvaderMiddleGfx, 11 , 8, WHITE);
  display.drawBitmap(XPos, 20, InvaderMiddleGfx, 11 , 8, BLACK);
  XPos += 1;
  if(XPos > 127)
    XPos = 0;
}

Take the text printing etc out of loop()

  • Draw the invader
  • Wait a bit, preferably without using delay(), but it will do as a start
  • Draw the invader in the background colour
  • Update the invader position

So yes, basically what you posted

This is better than the beginning, it isn't flickering as much as before thank you for the help.

Put a short delay() in before overwriting the invader and see what the effect is

It moves it slower but it is flickering less.

No surprise on either result. I don't think that you will be able to do much better. I am surprised that it works at all with the invader defined in PROGMEM as you are not using the special commands needed to access it

What happens if you put the array in RAM instead ?

I don't know, I am knew to this. What is a PROGMEM all I know is to use it when loading bitmaps.

What are the special commands?

Using PROGMEM in a variable declaration causes it to be stored in program memory rather than dynamic RAM thus leaving more room for other variables at the expense of space for the program itself

If you Google Arduino PROGMEM you will find many explanations of its use, but first I would try just removing PROGMEM from the declaration as at the moment you will not be short of RAM

Which Arduino board are you using ?

Arduino Uno

Ok another problem, How do I update a bigger area with the least amount of flickering.

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1351.h>

// OLED Display Dimesions (pixels)
#define OLED_WIDTH 128
#define OLED_HEIGHT 128

// OLED Display PINS
#define DIN_PIN 12
#define CLK_PIN 11
#define CS_PIN 10
#define DC_PIN 9
#define RST_PIN 8

// On / Off Button Pin
#define OnOff_TOGGLE_SWITCH_PIN 4

// OLED Colours
#define  BLACK           0x0000
#define BLUE            0x001F
#define RED             0xF800
#define GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

Adafruit_SSD1351 display = Adafruit_SSD1351(OLED_WIDTH, OLED_HEIGHT, CS_PIN, DC_PIN, DIN_PIN, CLK_PIN, RST_PIN);

// Alien Settings
#define NUM_ALIEN_COLUMNS 7
#define NUM_ALIEN_ROWS 3
#define X_START_OFFSET 6
#define SPACE_BETWEEN_ALIEN_COLUMNS 5
#define LARGEST_ALIEN_WIDTH 11
#define SPACE_BETWEEN_ROWS 9

// OLED Graphics
static const unsigned char PROGMEM InvaderTopGfx [] =
{
  B00011000,
  B00111100,
  B01111110,
  B11011011,
  B11111111,
  B00100100,
  B01011010,
  B10100101
};

static const unsigned char PROGMEM InvaderMiddleGfx [] =
{
  B00100000, B10000000,
  B00010001, B00000000,
  B00111111, B10000000,
  B01101110, B11000000,
  B11111111, B11100000,
  B10111111, B10100000,
  B10100000, B10100000,
  B00011011, B00000000
};

static const unsigned char PROGMEM InvaderBottomGfx [] =
{
  B00001111, B00000000,
  B01111111, B11100000,
  B11111111, B11110000,
  B11100110, B01110000,
  B11111111, B11100000,
  B00111001, B11000000,
  B01100110, B01100000,
  B00110000, B11000000
};

struct GameObjectStruct  {
    signed int X;
    signed int Y;  
};

struct AlienStruct  {
  GameObjectStruct Ord;
};

AlienStruct  Alien[NUM_ALIEN_COLUMNS][NUM_ALIEN_ROWS];

byte AlienWidth[]={8,11,12};  // top, middle ,bottom widths

void setup()
{
  Serial.begin(9600);
  Serial.println("Serial started on baud: 9600.");

  display.begin();
  InitAliens(0);
}

void loop()
{
  UpdateDisplay();
}

void UpdateDisplay()  
{
  display.fillScreen(BLACK);
  for(int across=0;across<NUM_ALIEN_COLUMNS;across++)
  {
    for(int down=0;down<NUM_ALIEN_ROWS;down++)
    {
      switch(down)  
      {
        case 0: 
          display.drawBitmap(Alien[across][down].Ord.X, Alien[across][down].Ord.Y,  InvaderTopGfx, AlienWidth[down], 8,WHITE);
          break;
        case 1: 
          display.drawBitmap(Alien[across][down].Ord.X, Alien[across][down].Ord.Y,  InvaderMiddleGfx, AlienWidth[down], 8,WHITE);
          break;
        default: 
          display.drawBitmap(Alien[across][down].Ord.X, Alien[across][down].Ord.Y,  InvaderBottomGfx, AlienWidth[down], 8,WHITE);
      }
    }
  }
}

void InitAliens(int YStart)  { 
  for(int across=0;across<NUM_ALIEN_COLUMNS;across++)  {
    for(int down=0;down<3;down++)  {
      Alien[across][down].Ord.X=X_START_OFFSET+(across*(LARGEST_ALIEN_WIDTH+SPACE_BETWEEN_ALIEN_COLUMNS))-down;  
      Alien[across][down].Ord.Y=YStart+(down*SPACE_BETWEEN_ROWS);
    }
  }
}

Sorry the code was wrong I updated it.
This is the new code. (All of this is from a tutorial)

I think that you are not going to win your battle with flicker. If the screen flickers badly displaying and moving 1 alien then it is bound to be worse displaying and moving 21 of them, don't you think ?

Sorry, but I don't have any useful suggestions beyond only updating the screen where and when you need to.

What has the tutorial got to say about it, if anything ?

They just use the display.clearDisplay(); (they have ssd1306) and then redraw all of them aliens and it doesn't flicker for them, but ssd1351 doesn't have that function.

Please post a link to the tutorial that the code came from. The page you previously posted a link to does not seem to have a link to the next part of the tutorial

Here Space Invaders Arduino OLED build Ep1 : Graphic plotting and movement - YouTube
This is the art I'm on Space Invaders on Arduino Part 2 - YouTube