This project requires previous experience with Arduino and SPI-driven TFT displays, I recommend first doing simpler projects before moving to this one.
Hardware constraintsThere are a couple of hardware limitations that are relevant to this project:
1.
Speed of drawing to the display: ILI9341 is a 320x240 16-bit display that uses SPI to communicate with the CPU. That presents a bit of a problem because drawing to the whole screen is somewhat slow. It's even slower if you attempt to draw to the screen multiple times per frame, so there should be as few draw commands (per frame) as possible. The way I mitigated this issue is by using two buffers using ESP's internal ram where I wrote everything into and then they are drawn to the display as bitmaps (more info below).
2.
Ram constraints: Since there is only a limited amount of RAM in ESP, only a part of the display is used for rendering.
3.
Transparency: The display uses rgb565 format and since it's missing the alpha component there is no direct way to achieve transparency between layers. My solution is when the buffers are overlayed, the color white (0xFFFF) is ignored, i.e considered transparent.
Game graphics were mostly made by screenshoting the original game and downscaling them. The tool I used to convert.bmp files to c arrays is ImageConverter565 (link in the tool section). There is a bug that exists in the program and heres how to fix it:
After the conversion we change the extention from.c to.h and open it. First thing is to remove the #include
statment, change prog_uint16_t
to const uint16_t
and if you want remove the size specifier. After that we take the size and divide it by 2 to get the total number of elements.
Now here's the bug, our calculated element count is 1224, but the program stopped adding pixels after 1216 (if there aren't 16 pixels per row it will skip adding them), we need to fill the missing pixels with 0xFFFF.
RenderingThere are two buffers I use inside the ESP where I put all the sprites before I draw them to the screen.
The groundGround sprites are 90px wide, so 4 of them can fit into the screen at a time. Game logic manages 5 of them, where initally the 5th one isn't drawn.
In the game, ground is the thing that moves (more precisely is dynamic on x coordinate) while the dino awlays stays in the same place (on the x coordinate). Main buffer is filled pixel by pixel by treating all of the current visible ground sprites as one array, 0, 0 would be first pixel in the first line of the first sprite, 320, 0 would be last pixel in the first line of the 4th array, 4, 1 would be the second pixel in the 4th line of the first array and etc. That makes the main array and our normalized one the same size, so it's directly copied to it.
Shifting
The same conept is applied as above, but starting and ending position of normalization is shifted by given amount (0 - 90 after that first ground elemnt is removed and a new sprite is added to the 5th place).
To preserve memory, and makes the main buffer "shorter" one more buffer is added where dino can jump. Since only dino can be in this array transparency and collision checking isn't used.
If there is enough clearance on the field, there is 40% chance the bird will spawn. If the bird is flying high in the air or low on ground is also randomly chosen. When the bird is entering or exiting the screen only the visible parts of it are proccessed.
This has been done pretty simple, above the ground line (normalized above line 15) before dino is overlayed on the buffer it is checked if the current pixel in the main buffer and the current pixel of the dino are both 0x528A (dark grey color used in the game) and sets the colided flag to true.
All the text is drawn using PressStart2P (here is a tutorial on how to use custom fonts with adafruit gfx library). Drawn text is cleared by displaying the same thing only in pure white color. Every 100 points score flashes visible/invisible 4 times.
Gameplay images- DinoGame folder needs to be in the libraries folder.
- This cannot be ported to arduino uno because of it's lack of RAM.
- You can change the games speed by sending a number (0-9) to the serial console at 115200 baud. Default speed is 0.
Comments
Please log in or sign up to comment.