TFT_eSPI : how to move a sprite with transparent background?

I'd like to move a sprite over a background image, so that the sprite does not leave a trace of its movement. Is this possible using TFT_eSPI?

So far, I know how to display a bmp image, create and display a sprite at a specific position with transparent background, but when I try to move it I don't know how to erase it before displaying it at the next position.

Would it be possible for example, before displaying it to save the background into another sprite?

I use a TTGO T-Display (ST7789 driver).
Thanks for your help.

Hi lesept,

that's why some controllers have multiple planes...

But David will know how. I assume soft scroll uses a similar technique.


           // The next functions can be used as a pair to copy screen blocks (or horizontal/vertical lines) to another location
           // Read a block of pixels to a data buffer, buffer is 16 bit and the size must be at least w * h
  void     readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data);
           // Write a block of pixels to the screen which have been read by readRect()
  void     pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data);

I have never "done sprites" but it should be fairly straightforward.

A Sprite will have W x H dimensions. Either Monochrome e.g. Opaque/Transparent or Full Colour where one special value means Transparent.

You read the Display memory W x H @ X,Y pixel coordinates into an SRAM buffer.
Then you can plot the Sprite.

Any subsequent move of the Sprite involves re-drawing the saved background from SRAM, reading the background for the new position and plotting the Sprite.

A 32x32 sprite is manageable i.e. 2048 bytes for the background save area.
Most movement will be 0 or 1 pixel in x, y directions. You only need to restore the 1 pixel stripe that has been revealed and read the 1 pixel stripe that is new. Manipulate the SRAM buffer to keep it in order.


Thanks Jean-Marc and David
If I understand well, readRect enables to store in a data buffer a rectangular portion of the image.

So if my sprite is 20x20pixels, and I want to display it at coordinates X, Y: I first need to save the content of the 20x20 pixels at this coordinates using readRect. Then, I display the sprite.
When the sprite moves, for example +1 pixel in Y direction, I use pushRect to erase the sprite, then save again the next rectangle, display the sprite at the new position, and so on...

Is that correct?

Yes. That is my guess.

Have a look at what Bodmer does in his examples.

20x20 is not too big. Obviously a 200x200 Sprite would take 100x longer for readRect() and pushRect()


Thanks David. I haven’t seen anything related to what I want to do in Bodmer’s examples, that’s why I asked the question.

I tried, but it seems the saved portion of the image is full black.
Here is the code doing it:

TFT_eSPI tft = TFT_eSPI(135, 240); // Invoke custom library
TFT_eSprite img = TFT_eSprite(&tft); // Sprite object
uint16_t bg[400] = {0};

void setup() {
  tft.setRotation(0);  // 0 & 2 Portrait. 1 & 3 landscape
  drawBmp("/Sapin.bmp", 0, 0);
  int x = 60;
  int y = 10;
  // Move 1 sprite containing a "transparent" colour
  for (int i = 0; i < 100; i++)
    tft.readRect(x, y, 20, 20, bg);
    drawStar(x, y);
    tft.pushRect(x, y, 20, 20, bg);

void loop() {

drawStar only draws a red X at given location, and I can see it moving down the display, but on a black background:

void drawStar(int x, int y)
  img.createSprite(20, 20);

  img.drawLine(0, 0, 20, 20, TFT_RED);
  img.drawLine(0, 20, 20, 0, TFT_RED);

  img.pushSprite(x, y, TFT_TRANSPARENT);

  // Delete it to free memory

If I comment the call to drawStar, I just see a black square moving down, so the problem lies in the read / push pair.
When I print the content of the bg array, it’s all zeros.


sorry, I didn't check if your display is readable, as you didn't provide a link!

LILYGO® TTGO T-Display ESP32 WiFi And Bluetooth Module Development Board 1.14 Inch LCD Control Board

If you look at the picture with pinouts, you see that the display isn't connected to MISO. It is write-only!


or could it be that the display has SDA_READ?

  #ifdef TFT_SDA_READ

I have a T-Display. It has ST7789 controller with bidirectional SDA (I think)

So I should be able to read it. I am not sure about TFT_eSPI though.
I will try this evening.


Thanks guys, it actually has this SDA_READ thing. Bodmer posted an answer on his github and it works now.

I had to install the latest version of the library and add a define.

#define TFT_SDA_READ   // Display has a bidirectional SDA pin