Home Archives About
moefh.github.io
The Magic Smoke Has Left the Building
Porting Loser Corps to the ESP32 - Part 2

More progress in porting Loser Corps to the ESP32 (see all posts about the port).

Here's a demo video (click to open Youtube):

Youtube video
Youtube video

(This video shows a slightly older version where collision detection was done with the image rectangle, not the character's clipping rectangle, which is why it looks a little wonky in a few places.)

As the video shows, you control a character in a map, walking and jumping around. I reworked some parts of the movement code, but it feels a lot like the original, although I think the jump is not high enough. The collision detection is pretty much untouched, except for what I absolutely had to do to make it run in the ESP32, which wasn't much.

The joystick I'm using is a common Arduino joystick shield. It's pretty cheap and easy to use, but it requires one input pin of the ESP32 for each button, and one analog input pin for each direction of the stick -- it's really just a bunch of of buttons and potentiometers conveniently placed on a PCB:

The Arduino joystick shield I'm using
The Arduino joystick shield I'm using

I've connected all buttons pins, but the code only uses the C button to jump and the X analog stick to move.

I've tried to use a Wiimote nunchuck and a Wiimote classic controller, but I didn't have much success. These controllers use an I2C interface to talk to the Wiimote, so it seems like they should be easy to use with the ESP32 -- and it actually works, but it's very unreliable. The controller stops replying for no apparent reason, a lot of times requiring an unplug/re-plug to start working again. I've tried it with no pullup resistors, 4.7K pullups, 10K pullups, all for nothing. The strangest thing is that it works perfectly with an Arduino Uno (using the same exact test code), even with no pullup resistors. I say people saying that the I2C part of the ESP32 Arduino library isn't that great, so maybe that's the problem?

Another nice option would be to use the Wiimote itself, which uses Bluetooth. That's probably the next thing I'll work on in this project.

Porting Loser Corps to the ESP32

(See all posts about the port)

I started porting Loser Corps, a video game I and a few friends made in the old days of 1998-1999, to the ESP32.

I'm using bitluni's ESP32Lib to generate the VGA output, and I'm still using my crappy homemade DAC with 2 bits per color component I showed in the last post. The only new addition is a little board I made to connect the pins from the ESP32 devkit to the VGA breakout board without the mess I had in the breadboard, and an improvised cardboard box to hold the VGA plug in place (it works surprisingly well). I'll probably make a nicer board and box when I add joystick input and sound output.

The code currently renders a static screen with the background filled with tiles, some sprites and some foreground tiles. It's probably a reasonable test of how fast things will render:

The whole setup
The whole setup

The game images look a little rough when converted to 64 colors, especially since the palette is fixed by the hardware, but I think I can get used to it:

Screenshot of the game
Screenshot of the game

I managed to get a descent render speed after I started writing to the screen 4 pixels at a time. The annoying thing about this whole thing is that because of the way the ESP32 I2S DMA works, the data in the framebuffer has to be set in a weird order:

pixels01234567...
address[2][3][0][1][6][7][4][5]...

Another annoying thing is that the VSync and HSync bits for the VGA signal have to go inside every pixel in the framebuffer. To make things fast, I pre-baked these bits in the image data, which means that if I want to change to a VGA mode that happens to have different VSync or HSync polarity, I'll have to re-convert the images and recompile everything. Not a big deal, but it's annoying.

Currently my code only supports placing images aligned horizontally to 4 pixels (i.e., the x coordinate must be a multiple of 4). With that, the trick of writing 4 pixels at a time, and not clearing the screen every frame (since I'm going to overwrite everything anyway), I managed to get around 150 frames per second. We'll have to see how bad it gets once I remove the restriction on the horizontal alignment.

All in all, I'm very pleased with the progress.

ESP32 VGA output

Some time ago I made a VGA connector with a simple DAC made of resistors to use with old FPGA board, but since the board has very little RAM I wasn't able to do anything too interesting (the DAC shown there has only 1 bit per color channel, I later made an improved one with 2 bits per channel). But as it turns out, some crazy people made the ESP32 output a VGA signal using I2S -- I just tested it and it seems to work perfectly!

I used FabGL by Fabrizio Di Vittorio, but there's also ESP32Lib by bitluni which I'll probably check out later. Here's one of FabGL's examples in action (pay no attention to the smudges on the monitor, it's very old):

ESP32 outputting to an old CRT monitor
ESP32 outputting to an old CRT monitor

Here's a close-up of the ESP32 showing the connected pins.

Showing the connected pins
Showing the connected pins

I'm using the default FabGL pinout, which is:

ESP32 pinConnection
23H Sync
15V Sync
22Red (high bit)
21Red (low bit)
19Green (high bit)
18Green (low bit)
5Blue (high bit)
4Blue (low bit)

And finally, here's my hacky VGA connector/DAC with 2 bits per color channel giving a total of 64 colors:

My homemade VGA connector/DAC
My homemade VGA connector/DAC

The other side of the board is kind of a mess (this was one of my first soldering jobs), but it works well enough. And, before you ask, all of the jumpers are inserted all the way in, but some have longer leads than others -- they're really crappy jumpers!

I might try to port Loser Corps to this thing. No idea how well it will work over Wifi, the network code is very simplistic and probably doesn't work well anywhere other than Ethernet. We'll see.