mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-10 16:49:36 +00:00
Prepare for display orientation part 1 (#2661)
This commit is contained in:
+33
-60
@@ -10,81 +10,54 @@
|
||||
|
||||
namespace ui::external_app::snake {
|
||||
|
||||
Ticker game_timer;
|
||||
|
||||
int snake_x[GRID_WIDTH * GRID_HEIGHT];
|
||||
int snake_y[GRID_WIDTH * GRID_HEIGHT];
|
||||
int snake_length = 1;
|
||||
int snake_dx = 1;
|
||||
int snake_dy = 0;
|
||||
int food_x, food_y;
|
||||
int score = 0;
|
||||
int game_state = STATE_MENU;
|
||||
bool initialized = false;
|
||||
|
||||
const Color pp_colors[] = {
|
||||
Color::white(),
|
||||
Color::blue(),
|
||||
Color::yellow(),
|
||||
Color::purple(),
|
||||
Color::green(),
|
||||
Color::red(),
|
||||
Color::magenta(),
|
||||
Color::orange(),
|
||||
Color::black(),
|
||||
};
|
||||
|
||||
Painter painter;
|
||||
|
||||
bool but_RIGHT = false;
|
||||
bool but_LEFT = false;
|
||||
bool but_SELECT = false;
|
||||
|
||||
static Callback game_update_callback = nullptr;
|
||||
static uint32_t game_update_timeout = 0;
|
||||
static uint32_t game_update_counter = 0;
|
||||
|
||||
void cls() {
|
||||
void SnakeView::cls() {
|
||||
painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black());
|
||||
}
|
||||
|
||||
void background(int color) {
|
||||
void SnakeView::background(int color) {
|
||||
(void)color;
|
||||
}
|
||||
|
||||
void fillrect(int x1, int y1, int x2, int y2, int color) {
|
||||
void SnakeView::fillrect(int x1, int y1, int x2, int y2, int color) {
|
||||
painter.fill_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
|
||||
}
|
||||
|
||||
void rect(int x1, int y1, int x2, int y2, int color) {
|
||||
void SnakeView::rect(int x1, int y1, int x2, int y2, int color) {
|
||||
painter.draw_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
|
||||
}
|
||||
|
||||
void check_game_timer() {
|
||||
void SnakeView::check_game_timer() {
|
||||
if (game_update_callback) {
|
||||
if (++game_update_counter >= game_update_timeout) {
|
||||
game_update_counter = 0;
|
||||
game_update_callback();
|
||||
game_timer_check();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ticker::attach(Callback func, double delay_sec) {
|
||||
game_update_callback = func;
|
||||
void SnakeView::attach(double delay_sec) {
|
||||
game_update_callback = true;
|
||||
game_update_timeout = delay_sec * 60;
|
||||
}
|
||||
|
||||
void Ticker::detach() {
|
||||
game_update_callback = nullptr;
|
||||
void SnakeView::detach() {
|
||||
game_update_callback = false;
|
||||
}
|
||||
|
||||
void game_timer_check() {
|
||||
void SnakeView::game_timer_check() {
|
||||
if (game_state == STATE_PLAYING) {
|
||||
update_game();
|
||||
}
|
||||
}
|
||||
|
||||
void init_game() {
|
||||
void SnakeView::init_game() {
|
||||
SCREEN_WIDTH = screen_width;
|
||||
SCREEN_HEIGHT = screen_height;
|
||||
GAME_AREA_HEIGHT = (SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2);
|
||||
GRID_WIDTH = ((SCREEN_WIDTH - 2) / SNAKE_SIZE);
|
||||
GRID_HEIGHT = (GAME_AREA_HEIGHT / SNAKE_SIZE);
|
||||
snake_x.resize(GRID_WIDTH * GRID_HEIGHT);
|
||||
snake_y.resize(GRID_WIDTH * GRID_HEIGHT);
|
||||
snake_x[0] = GRID_WIDTH / 2;
|
||||
snake_y[0] = GRID_HEIGHT / 2;
|
||||
snake_length = 1;
|
||||
@@ -99,7 +72,7 @@ void init_game() {
|
||||
}
|
||||
}
|
||||
|
||||
void spawn_food() {
|
||||
void SnakeView::spawn_food() {
|
||||
bool valid;
|
||||
do {
|
||||
food_x = rand() % GRID_WIDTH;
|
||||
@@ -114,7 +87,7 @@ void spawn_food() {
|
||||
} while (!valid);
|
||||
}
|
||||
|
||||
void update_game() {
|
||||
void SnakeView::update_game() {
|
||||
int new_x = snake_x[0] + snake_dx;
|
||||
int new_y = snake_y[0] + snake_dy;
|
||||
bool ate_food = (new_x == food_x && new_y == food_y);
|
||||
@@ -152,7 +125,7 @@ void update_game() {
|
||||
}
|
||||
}
|
||||
|
||||
bool check_collision() {
|
||||
bool SnakeView::check_collision() {
|
||||
if (snake_x[0] < 0 || snake_x[0] >= GRID_WIDTH || snake_y[0] < 0 || snake_y[0] >= GRID_HEIGHT) {
|
||||
return true;
|
||||
}
|
||||
@@ -164,7 +137,7 @@ bool check_collision() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw_screen() {
|
||||
void SnakeView::draw_screen() {
|
||||
cls();
|
||||
background(COLOR_BACKGROUND);
|
||||
draw_borders();
|
||||
@@ -173,44 +146,44 @@ void draw_screen() {
|
||||
draw_score();
|
||||
}
|
||||
|
||||
void draw_snake() {
|
||||
void SnakeView::draw_snake() {
|
||||
fillrect(1 + snake_x[0] * SNAKE_SIZE, GAME_AREA_TOP + snake_y[0] * SNAKE_SIZE,
|
||||
1 + snake_x[0] * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + snake_y[0] * SNAKE_SIZE + SNAKE_SIZE, COLOR_SNAKE);
|
||||
}
|
||||
|
||||
void draw_full_snake() {
|
||||
void SnakeView::draw_full_snake() {
|
||||
for (int i = 0; i < snake_length; i++) {
|
||||
fillrect(1 + snake_x[i] * SNAKE_SIZE, GAME_AREA_TOP + snake_y[i] * SNAKE_SIZE,
|
||||
1 + snake_x[i] * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + snake_y[i] * SNAKE_SIZE + SNAKE_SIZE, COLOR_SNAKE);
|
||||
}
|
||||
}
|
||||
|
||||
void erase_tail(int x, int y) {
|
||||
void SnakeView::erase_tail(int x, int y) {
|
||||
fillrect(1 + x * SNAKE_SIZE, GAME_AREA_TOP + y * SNAKE_SIZE,
|
||||
1 + x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + y * SNAKE_SIZE + SNAKE_SIZE, COLOR_BACKGROUND);
|
||||
}
|
||||
|
||||
void draw_food() {
|
||||
void SnakeView::draw_food() {
|
||||
fillrect(1 + food_x * SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE,
|
||||
1 + food_x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE + SNAKE_SIZE, COLOR_FOOD);
|
||||
}
|
||||
|
||||
void erase_food() {
|
||||
void SnakeView::erase_food() {
|
||||
fillrect(1 + food_x * SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE,
|
||||
1 + food_x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE + SNAKE_SIZE, COLOR_BACKGROUND);
|
||||
}
|
||||
|
||||
void draw_score() {
|
||||
void SnakeView::draw_score() {
|
||||
auto style = *ui::Theme::getInstance()->fg_blue;
|
||||
painter.draw_string({5, 5}, style, "Score: " + std::to_string(score));
|
||||
}
|
||||
|
||||
void draw_borders() {
|
||||
void SnakeView::draw_borders() {
|
||||
rect(0, GAME_AREA_TOP - 1, SCREEN_WIDTH, GAME_AREA_TOP, COLOR_BORDER);
|
||||
rect(0, GAME_AREA_TOP, SCREEN_WIDTH, SCREEN_HEIGHT, COLOR_BORDER);
|
||||
}
|
||||
|
||||
void show_menu() {
|
||||
void SnakeView::show_menu() {
|
||||
cls();
|
||||
background(COLOR_BACKGROUND);
|
||||
auto style_yellow = *ui::Theme::getInstance()->fg_yellow;
|
||||
@@ -223,7 +196,7 @@ void show_menu() {
|
||||
painter.draw_string({15, 240}, style_green, "** PRESS SELECT TO START **");
|
||||
}
|
||||
|
||||
void show_game_over() {
|
||||
void SnakeView::show_game_over() {
|
||||
cls();
|
||||
background(COLOR_BACKGROUND);
|
||||
auto style_red = *ui::Theme::getInstance()->fg_red;
|
||||
@@ -238,7 +211,7 @@ void show_game_over() {
|
||||
SnakeView::SnakeView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
add_children({&dummy});
|
||||
game_timer.attach(&game_timer_check, 1.0 / 5.0);
|
||||
attach(1.0 / 5.0);
|
||||
}
|
||||
|
||||
void SnakeView::on_show() {
|
||||
|
||||
+57
-56
@@ -32,36 +32,11 @@ enum {
|
||||
Black,
|
||||
};
|
||||
|
||||
extern const Color pp_colors[];
|
||||
extern Painter painter;
|
||||
extern bool but_RIGHT;
|
||||
extern bool but_LEFT;
|
||||
extern bool but_SELECT;
|
||||
|
||||
void cls();
|
||||
void background(int color);
|
||||
void fillrect(int x1, int y1, int x2, int y2, int color);
|
||||
void rect(int x1, int y1, int x2, int y2, int color);
|
||||
|
||||
#define wait(x) chThdSleepMilliseconds(x * 1000)
|
||||
|
||||
using Callback = void (*)(void);
|
||||
|
||||
class Ticker {
|
||||
public:
|
||||
Ticker() = default;
|
||||
void attach(Callback func, double delay_sec);
|
||||
void detach();
|
||||
};
|
||||
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 320
|
||||
#define SNAKE_SIZE 10
|
||||
#define INFO_BAR_HEIGHT 25
|
||||
#define GAME_AREA_TOP (INFO_BAR_HEIGHT + 1)
|
||||
#define GAME_AREA_HEIGHT (SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2)
|
||||
#define GRID_WIDTH ((SCREEN_WIDTH - 2) / SNAKE_SIZE)
|
||||
#define GRID_HEIGHT (GAME_AREA_HEIGHT / SNAKE_SIZE)
|
||||
#define STATE_MENU 0
|
||||
#define STATE_PLAYING 1
|
||||
#define STATE_GAME_OVER 2
|
||||
@@ -71,35 +46,6 @@ class Ticker {
|
||||
#define COLOR_FOOD Red
|
||||
#define COLOR_BORDER White
|
||||
|
||||
extern Ticker game_timer;
|
||||
|
||||
extern int snake_x[GRID_WIDTH * GRID_HEIGHT];
|
||||
extern int snake_y[GRID_WIDTH * GRID_HEIGHT];
|
||||
extern int snake_length;
|
||||
extern int snake_dx;
|
||||
extern int snake_dy;
|
||||
extern int food_x;
|
||||
extern int food_y;
|
||||
extern int score;
|
||||
extern int game_state;
|
||||
extern bool initialized;
|
||||
|
||||
void game_timer_check();
|
||||
void init_game();
|
||||
void update_game();
|
||||
void draw_screen();
|
||||
void draw_snake();
|
||||
void draw_full_snake();
|
||||
void erase_tail(int x, int y);
|
||||
void draw_food();
|
||||
void erase_food();
|
||||
void draw_score();
|
||||
void draw_borders();
|
||||
void spawn_food();
|
||||
bool check_collision();
|
||||
void show_menu();
|
||||
void show_game_over();
|
||||
|
||||
class SnakeView : public View {
|
||||
public:
|
||||
SnakeView(NavigationView& nav);
|
||||
@@ -112,12 +58,67 @@ class SnakeView : public View {
|
||||
void frame_sync();
|
||||
bool on_key(KeyEvent key) override;
|
||||
|
||||
void cls();
|
||||
void background(int color);
|
||||
void fillrect(int x1, int y1, int x2, int y2, int color);
|
||||
void rect(int x1, int y1, int x2, int y2, int color);
|
||||
void game_timer_check();
|
||||
void init_game();
|
||||
void update_game();
|
||||
void draw_screen();
|
||||
void draw_snake();
|
||||
void draw_full_snake();
|
||||
void erase_tail(int x, int y);
|
||||
void draw_food();
|
||||
void erase_food();
|
||||
void draw_score();
|
||||
void draw_borders();
|
||||
void spawn_food();
|
||||
bool check_collision();
|
||||
void show_menu();
|
||||
void show_game_over();
|
||||
void check_game_timer();
|
||||
|
||||
void attach(double delay_sec);
|
||||
void detach();
|
||||
|
||||
private:
|
||||
bool initialized = false;
|
||||
const Color pp_colors[9] = {
|
||||
Color::white(),
|
||||
Color::blue(),
|
||||
Color::yellow(),
|
||||
Color::purple(),
|
||||
Color::green(),
|
||||
Color::red(),
|
||||
Color::magenta(),
|
||||
Color::orange(),
|
||||
Color::black(),
|
||||
};
|
||||
NavigationView& nav_;
|
||||
Painter painter{};
|
||||
|
||||
std::vector<int> snake_x{}; //[GRID_WIDTH * GRID_HEIGHT];
|
||||
std::vector<int> snake_y{}; //[GRID_WIDTH * GRID_HEIGHT];
|
||||
int snake_length = 1;
|
||||
int snake_dx = 1;
|
||||
int snake_dy = 0;
|
||||
int food_x = 0, food_y = 0;
|
||||
int score = 0;
|
||||
int game_state = STATE_MENU;
|
||||
bool initialized = false;
|
||||
|
||||
int SCREEN_WIDTH = 0;
|
||||
int SCREEN_HEIGHT = 0;
|
||||
int GAME_AREA_HEIGHT = 0; //(SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2);
|
||||
int GRID_WIDTH = 0; // ((SCREEN_WIDTH - 2) / SNAKE_SIZE);
|
||||
int GRID_HEIGHT = 0; //(GAME_AREA_HEIGHT / SNAKE_SIZE);
|
||||
|
||||
bool game_update_callback = false;
|
||||
double game_update_timeout = 0;
|
||||
uint32_t game_update_counter = 0;
|
||||
|
||||
Button dummy{
|
||||
{240, 0, 0, 0},
|
||||
{screen_width, 0, 0, 0},
|
||||
""};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
|
||||
Reference in New Issue
Block a user