| .. | |||
| README.md | 6 months ago | ||
| arkanoid_game.c | 6 months ago | ||
| arkanoid_game.h | 6 months ago | ||
| game_drawing.c | 6 months ago | ||
| game_drawing.h | 6 months ago | ||
| game_framework.h | 6 months ago | ||
| game_menu.c | 6 months ago | ||
| game_menu.h | 6 months ago | ||
| jump_bird_game.c | 6 months ago | ||
| jump_bird_game.h | 6 months ago | ||
| jump_bird_game_input_queue.c | 6 months ago | ||
| jump_bird_game_input_queue.h | 6 months ago | ||
This guide outlines the steps to integrate a new game into the existing game selection and display framework on the ESP32.
The ESP32 game system is organized as follows:
main.c Initializes core tasks (buttons, LEDs, display) and orchestrates the game selection menu and game execution loop.
game_menu.h / game_menu.c Manages the game selection menu displayed on the OLED.
display_task.h / display_task.c Handles the OLED display: drawing the menu, game graphics, game over screens, and transitions.
game_framework.h Defines the game_t interface (a struct of function pointers) that all games must implement, enabling standardized interaction.
game_drawing.h / game_drawing.c Provides common drawing utilities (e.g., draw_filled_rect, draw_rectangle_outline) for use across games.
button_task.h / button_task.c Handles button inputs and pushes them into a shared input queue.
You will mainly work with:
main.cgame_framework.h (typically not required unless extending the interface)Create two new files in tasks/game/:
my_new_game.hmy_new_game.cmy_new_game.hDeclare your game's external game_t instance:
#ifndef MY_NEW_GAME_H #define MY_NEW_GAME_H #include "game_framework.h" // Required for game_t extern const game_t MyNewGame; #endif // MY_NEW_GAME_H
my_new_game.cImplement your game by adhering to the game_t interface.
#include "freertos/FreeRTOS.h" #include "freertos/queue.h" #include "esp_random.h" #include "ssd1306.h" #include "game_framework.h" #include "game_drawing.h"
Declare your game state:
static bool s_game_is_active = false; static bool s_game_over = false; static int s_score = 0; static QueueHandle_t s_game_input_queue_global = NULL;
game_t Functionsinit_gamestatic void my_new_game_init_game_impl() {
// Reset state
s_game_is_active = true;
s_game_over = false;
s_score = 0;
if (s_game_input_queue_global) {
xQueueReset(s_game_input_queue_global);
}
}
handle_inputstatic void my_new_game_handle_input_impl() {
int input_value;
if (xQueueReceive(s_game_input_queue_global, &input_value, 0)) {
// Handle input_value (e.g., move player)
}
}
update_game_statestatic bool my_new_game_update_game_state_impl() {
// Game logic here
if (/* game over condition */) {
s_game_over = true;
return true;
}
return false;
}
draw_gamestatic void my_new_game_draw_game_impl(SSD1306_t *dev) {
draw_filled_rect(dev, 0, GAME_PLAY_AREA_START_Y, OLED_WIDTH - 1, OLED_HEIGHT - 1, false);
draw_rectangle_outline(dev, 0, GAME_PLAY_AREA_START_Y - 1, OLED_WIDTH - 1, OLED_HEIGHT - 1, true);
// Draw player, enemies, etc. using game_drawing.h functions
}
⚠️ Note: Do not call
ssd1306_show_buffer()or draw the score—these are handled bydisplay_task.c.
get_scorestatic int my_new_game_get_score_impl() {
return s_score;
}
is_activestatic bool my_new_game_is_active_impl() {
return s_game_is_active && !s_game_over;
}
set_activestatic void my_new_game_set_active_impl(bool active) {
s_game_is_active = active;
}
get_input_queue / set_input_queuestatic QueueHandle_t my_new_game_get_input_queue_impl(void) {
return s_game_input_queue_global;
}
static void my_new_game_set_input_queue_impl(QueueHandle_t queue) {
s_game_input_queue_global = queue;
}
game_t Instanceconst game_t MyNewGame = {
.init_game = my_new_game_init_game_impl,
.handle_input = my_new_game_handle_input_impl,
.update_game_state = my_new_game_update_game_state_impl,
.draw_game = my_new_game_draw_game_impl,
.get_score = my_new_game_get_score_impl,
.is_active = my_new_game_is_active_impl,
.set_active = my_new_game_set_active_impl,
.get_input_queue = my_new_game_get_input_queue_impl,
.set_input_queue = my_new_game_set_input_queue_impl,
};
main.cAdd at the top of main.c:
#include "tasks/game/my_new_game.h"
Find the game_menu_items[] array and append your game:
const menu_item_t game_menu_items[] = {
{.name = "JUMP BIRD", .game_instance = &JumpBirdGame},
{.name = "ARKANOID", .game_instance = &ArkanoidGame},
{.name = "MY NEW GAME", .game_instance = &MyNewGame}, // Your game
};
idf.py clean idf.py build
idf.py flash
idf.py monitor
You should now see "MY NEW GAME" on the OLED menu. Selecting it will run your new game.
By following this guide, you will:
game_t interface