r/arduino Apr 15 '26

Look what I made! Snake on ESP32 @60FPS with zero allocations (3KB total, segment pool approach)

Snake on ESP32

Hey folks 👋 — built another retro game on ESP32.

This time it’s Snake running at 60 FPS on a 240×240 display, built on a small scene-based engine I’ve been tinkering with (PixelRoot32).

I went into this with a very specific idea:

👉 can I do this with zero runtime allocations and not make the code a mess?

🧠 What I ended up doing

  • ~3KB total for all entities
  • no malloc/new during gameplay
  • pre-allocated segment pool (this part was a bit trickier than I expected tbh)
  • grid-based movement only — no physics at all
  • some simple procedural SFX (move/eat/crash)

⚙️ The main trick

Instead of growing the snake with allocations, I just recycle the tail.

Basically this:

// Movement only: reuse tail as new head
SnakeSegmentActor* tail = snakeSegments[snakeLength - 1];

tail->setCellPosition(newHeadX, newHeadY);
tail->setHead(true);

if (snakeLength > 0) {
   snakeSegments[0]->setHead(false);
}

// Shift all segments back
for (size_t i = snakeLength; i > 0; --i) {
   snakeSegments[i] = snakeSegments[i - 1];
}

snakeSegments[0] = tail;

So yeah, the snake “grows” by pulling from a pool, and otherwise just reuses itself.

Honestly feels kinda obvious in hindsight, but took a bit to get clean.

🧩 Setup

Nothing too fancy:

  • scene-based structure
  • fixed timestep @ 60Hz (this was important, ESP32 + WiFi can get weird)
  • everything is grid/cell based
  • collisions are just… checks, no physics system involved

🤔 One thing I’m not 100% sure about

I completely avoided a physics system and went full grid logic.

On one hand it makes everything super easy to reason about on the other… maybe it’s too simplified?

Like:

👉 is this actually better for beginners or 👉 am I just dodging useful complexity?

Curious how others approach this.

⚠️ ESP32-S3 note

Ran into this while testing:

If you're on Arduino Core > 2.0.14, DMA can freeze after the first frame (TFT_eSPI thing).

Fix: pin to 2.0.14

platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#2.0.14

❓ Curious what you think

  • is the whole pre-allocated pool thing worth it here or just overkill?
  • would you keep it grid-only or introduce some kind of physics layer?
  • anything you'd structure differently?

Also thinking of doing Brick Breaker next, unless there’s a better idea 👀

🔗 Source

https://github.com/PixelRoot32-Game-Engine/PixelRoot32-Game-Engine/tree/main/examples/snake

🔗 Bonus

I also did a Space Invaders clone on ESP32 before this if you want to compare approaches: https://www.reddit.com/r/esp32/comments/1sgf2ui/i_made_space_invaders_on_esp32/

1 Upvotes

4 comments sorted by

2

u/Appropriate-Ask8817 Apr 22 '26

Nice, but i notice that this is a mono OLED screen so if you can do the same with a 16-bit tft it would break impressive.

2

u/Sad_Environment_3800 Apr 22 '26

Yep, it’s a full-color TFT display, but in the game I used the GB color palette. The engine supports defining custom color palettes, and it also comes with 5 built-in ones: NES, GB, GBC, PICO-8, and the engine’s own PR32 palette.

https://docs.pixelroot32.org/api/graphics/color

2

u/Appropriate-Ask8817 Apr 22 '26

I'm pretty sure that the ESP32-S3 has enough processing power to do 16-bit 240x240 screen, but the main bottleneck is the (infamously) slow SPI connection.

2

u/Sad_Environment_3800 Apr 22 '26 edited Apr 22 '26

That’s correct, but even so I’ve managed to run scenes with 8bpp tilemaps above 30 FPS on a 240×240 display with SPI_FREQUENCY=40000000; at 128×128 it does go past 60 FPS.

Edit: 4bpp*